From da74b0371d0c9b3f0f67588928c5f2c992fa2174 Mon Sep 17 00:00:00 2001 From: Thom de Jong Date: Tue, 5 Dec 2023 08:05:43 +0100 Subject: [PATCH] Add ObjectPool reading, writing and manipulations (#23) * Add ObjectPool reading, writing and manipulations * Update src/object_pool/mod.rs Co-authored-by: Adrian Del Grosso <10929341+ad3154@users.noreply.github.com> Signed-off-by: Thom de Jong * Update src/object_pool/mod.rs Co-authored-by: Adrian Del Grosso <10929341+ad3154@users.noreply.github.com> Signed-off-by: Thom de Jong * Update src/object_pool/mod.rs Co-authored-by: Adrian Del Grosso <10929341+ad3154@users.noreply.github.com> Signed-off-by: Thom de Jong * integrating unit tests for object pool (to be continued) * continue unit test and adding more specific option specifications * continue unit test from_iop * continue unit test from_iop and simplification of pool object design * GwnDaan review fixes * reader.rs refactoring * pass id to read functions * format * fix build * format * clippy warnings * writer.rs refactoring (for unit testing) * implement code planes * Renaming and typing * example doc * some validation stuff * .. * validate bool * fix read_bool * colour refactoring and rework * add working set specific unit test * rework from_iop unit test (to be continued) * todo working set read test * added nullable object id * .iop update * lint * .. * refactoring * lint * corrected test read_working_set_test * refactor object attributes * fix bug -> u8 not u16 * complete object option encapsulation * add EQ to NAME * remove todo * remove tests to fix them later --------- Signed-off-by: Thom de Jong Signed-off-by: Daan Steenbergen Co-authored-by: Adrian Del Grosso <10929341+ad3154@users.noreply.github.com> Co-authored-by: Jannes Brands Co-authored-by: Jannes Brands Co-authored-by: Daan Steenbergen --- Cargo.toml | 2 + resources/test/AgIsoStack-rs-test-pool.iop | Bin 0 -> 3073 bytes src/lib.rs | 1 + src/network_management/name.rs | 8 +- src/object_pool/colour.rs | 339 +++++ src/object_pool/mod.rs | 22 + src/object_pool/object.rs | 742 +++++++++++ src/object_pool/object_attributes.rs | 1068 +++++++++++++++ src/object_pool/object_id.rs | 115 ++ src/object_pool/object_pool.rs | 327 +++++ src/object_pool/object_type.rs | 170 +++ src/object_pool/reader.rs | 1384 ++++++++++++++++++++ src/object_pool/vt_version.rs | 45 + src/object_pool/writer.rs | 778 +++++++++++ 14 files changed, 5000 insertions(+), 1 deletion(-) create mode 100644 resources/test/AgIsoStack-rs-test-pool.iop create mode 100644 src/object_pool/colour.rs create mode 100644 src/object_pool/mod.rs create mode 100644 src/object_pool/object.rs create mode 100644 src/object_pool/object_attributes.rs create mode 100644 src/object_pool/object_id.rs create mode 100644 src/object_pool/object_pool.rs create mode 100644 src/object_pool/object_type.rs create mode 100644 src/object_pool/reader.rs create mode 100644 src/object_pool/vt_version.rs create mode 100644 src/object_pool/writer.rs diff --git a/Cargo.toml b/Cargo.toml index 5d79d06..c9efc1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,8 +7,10 @@ description = "A Free ISO-11783 and J1939 CAN Stack" keywords = ["agriculture", "can", "canbus", "isobus", "j1939", "agritech", "smart-farming", "iso11783"] [dependencies] +bitvec = "1.0.1" rand = "0.8.5" socketcan = { version = "2.0.0", optional = true } +strum_macros = "0.25.2" [features] default = [] diff --git a/resources/test/AgIsoStack-rs-test-pool.iop b/resources/test/AgIsoStack-rs-test-pool.iop new file mode 100644 index 0000000000000000000000000000000000000000..eb5d13e36cc9b4835a0b8f100c3fe11130864886 GIT binary patch literal 3073 zcmeH}k5`>@9LGOTx4P}#T5Xj|tWBG>yUpfaB}6lX{0fUgGU~BH8yaP2cFmB?F=TrD zDnDk^un=o@C>#`D3}HW&-D`|&hajHM`lWJv!9s3V~Qk6+H*Wo zAS1p!uASZjNt3#&JZY6J?g(61mKFBV>2Ljz_-fA)@iWiQwKYD{ZAn97Lt<3S zzY`XvL{A`oOpGO#?Dp-|dvr;<+w#cPQmv8ZWW@M!WNqg$0wr?(#g|O9c*ik*rdiuc zMe8Ld0~~aRk6=DG7CG?b%50;vUVF}n&zof??J$!hQs!0G)v~5{3MsXAm0DUyMa$g9 zwY3XtNL;M(W$g@&{U@%30`sm30r5(Anbs~B+4O|^%|^86jO{MVB>l2(J}F3;Ces+U zZhnL-G$c#1XtUUgaSRcO^RB59sTg%$R4_hCGDTuDy`x$ZI=Rd(ObpG7OQRp~wc`l|GX#MJr>D=4ybBG)i_#>7bxnUh@yPtBUe@&jy@)T&arckJN|@%6Hhw1@RU zeEF3%IP~>5-+uS~4?q6&^Do1{{`ULG?md6({qrw9vUd7tdIr|dNTYoA2>BFBQhGMb z6jR2d$#Xxu{t`Z4Gt(^0aAeiHaMVwMe&0UHaMUFBXpsI4Gt*a z0YB(qg98c}fFE?Q!2tzK!Vfx_(*Xqp!Vm7i4)3#~B{+W2!3GBuupoZW!3GBuV1g;= zV1ua<1>E2V9c*ww0iF0k4>>{Sq_XgXE@TR9a6kb;@PiIEIG}*Q_(2C798kbw_(2C7 z98iD(LZO3gY8gyTbHNXKC@bi+=A^@vE`A6JrUXs7F&IDSV9LXkg4uQgn5{J1X12&| zhe z?CflvpP#P_3k!8|aj`BhFW1%8)w;H}Rxew&OgA<*>ZYb9-O|#c+uGW6M@NV5>gv+H zy}i1xuTS^)_v@jdAw4`itb6x;0QiBjqx(Jp{1B_YQD?Qg(7E`$I8 literal 0 HcmV?d00001 diff --git a/src/lib.rs b/src/lib.rs index 2b835fb..b3b85af 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,3 +5,4 @@ pub mod driver; pub mod network_management; +pub mod object_pool; diff --git a/src/network_management/name.rs b/src/network_management/name.rs index 5818455..00f0f90 100644 --- a/src/network_management/name.rs +++ b/src/network_management/name.rs @@ -15,7 +15,7 @@ pub enum NameField { SelfConfigurableAddress(bool), } -#[derive(Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct NAME { raw_name: u64, } @@ -198,6 +198,12 @@ impl From for u64 { } } +impl From for [u8; 8] { + fn from(name: NAME) -> Self { + name.raw_name.to_le_bytes() + } +} + #[derive(Default)] pub struct NameBuilder { self_configurable_address: bool, diff --git a/src/object_pool/colour.rs b/src/object_pool/colour.rs new file mode 100644 index 0000000..7d0af04 --- /dev/null +++ b/src/object_pool/colour.rs @@ -0,0 +1,339 @@ +#[derive(Debug, Clone, Copy, PartialEq)] +#[non_exhaustive] +pub struct Colour { + pub id: u8, + pub a: u8, + pub r: u8, + pub g: u8, + pub b: u8, +} + +impl Colour { + pub fn new_by_id(id: u8) -> Self { + Colour::COLOUR_PALETTE[id as usize] + } + + pub fn new_by_rgb(r: u8, g: u8, b: u8) -> Self { + for colour in Colour::COLOUR_PALETTE.iter() { + if colour.r == r && colour.g == g && colour.b == b { + return *colour; + } + } + + Colour::BLACK + } + + pub fn new_by_rgba(r: u8, g: u8, b: u8, _a: u8) -> Self { + Self::new_by_rgb(r, g, b) + } + + pub fn as_rgb(&self) -> [u8; 3] { + [self.r, self.g, self.b] + } + + pub fn as_rgba(&self) -> [u8; 4] { + [self.r, self.g, self.b, self.a] + } + + pub const BLACK: Colour = Colour::COLOUR_PALETTE[0]; + pub const WHITE: Colour = Colour::COLOUR_PALETTE[1]; + pub const GREEN: Colour = Colour::COLOUR_PALETTE[2]; + pub const TEAL: Colour = Colour::COLOUR_PALETTE[3]; + pub const MAROON: Colour = Colour::COLOUR_PALETTE[4]; + pub const PURPLE: Colour = Colour::COLOUR_PALETTE[5]; + pub const OLIVE: Colour = Colour::COLOUR_PALETTE[6]; + pub const SILVER: Colour = Colour::COLOUR_PALETTE[7]; + pub const GREY: Colour = Colour::COLOUR_PALETTE[8]; + pub const BLUE: Colour = Colour::COLOUR_PALETTE[9]; + pub const LIME: Colour = Colour::COLOUR_PALETTE[10]; + pub const CYAN: Colour = Colour::COLOUR_PALETTE[11]; + pub const RED: Colour = Colour::COLOUR_PALETTE[12]; + pub const MAGENTA: Colour = Colour::COLOUR_PALETTE[13]; + pub const YELLOW: Colour = Colour::COLOUR_PALETTE[14]; + pub const NAVY: Colour = Colour::COLOUR_PALETTE[15]; + + #[rustfmt::skip] // Skip formatting the lines + pub const COLOUR_PALETTE: [Colour; 256] = [ + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 0 }, + Colour { r: 0xFF, g: 0xFF, b: 0xFF, a: 0xFF, id: 1 }, + Colour { r: 0x00, g: 0x99, b: 0x00, a: 0xFF, id: 2 }, + Colour { r: 0x00, g: 0x99, b: 0x99, a: 0xFF, id: 3 }, + Colour { r: 0x99, g: 0x00, b: 0x00, a: 0xFF, id: 4 }, + Colour { r: 0x99, g: 0x00, b: 0x99, a: 0xFF, id: 5 }, + Colour { r: 0x99, g: 0x99, b: 0x00, a: 0xFF, id: 6 }, + Colour { r: 0xCC, g: 0xCC, b: 0xCC, a: 0xFF, id: 7 }, + Colour { r: 0x99, g: 0x99, b: 0x99, a: 0xFF, id: 8 }, + Colour { r: 0x00, g: 0x00, b: 0xFF, a: 0xFF, id: 9 }, + Colour { r: 0x00, g: 0xFF, b: 0x00, a: 0xFF, id: 10 }, + Colour { r: 0x00, g: 0xFF, b: 0xFF, a: 0xFF, id: 11 }, + Colour { r: 0xFF, g: 0x00, b: 0x00, a: 0xFF, id: 12 }, + Colour { r: 0xFF, g: 0x00, b: 0xFF, a: 0xFF, id: 13 }, + Colour { r: 0xFF, g: 0xFF, b: 0x00, a: 0xFF, id: 14 }, + Colour { r: 0x00, g: 0x00, b: 0x99, a: 0xFF, id: 15 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 16 }, + Colour { r: 0x00, g: 0x00, b: 0x33, a: 0xFF, id: 17 }, + Colour { r: 0x00, g: 0x00, b: 0x66, a: 0xFF, id: 18 }, + Colour { r: 0x00, g: 0x00, b: 0x99, a: 0xFF, id: 19 }, + Colour { r: 0x00, g: 0x00, b: 0xCC, a: 0xFF, id: 20 }, + Colour { r: 0x00, g: 0x00, b: 0xFF, a: 0xFF, id: 21 }, + Colour { r: 0x00, g: 0x33, b: 0x00, a: 0xFF, id: 22 }, + Colour { r: 0x00, g: 0x33, b: 0x33, a: 0xFF, id: 23 }, + Colour { r: 0x00, g: 0x33, b: 0x66, a: 0xFF, id: 24 }, + Colour { r: 0x00, g: 0x33, b: 0x99, a: 0xFF, id: 25 }, + Colour { r: 0x00, g: 0x33, b: 0xCC, a: 0xFF, id: 26 }, + Colour { r: 0x00, g: 0x33, b: 0xFF, a: 0xFF, id: 27 }, + Colour { r: 0x00, g: 0x66, b: 0x00, a: 0xFF, id: 28 }, + Colour { r: 0x00, g: 0x66, b: 0x33, a: 0xFF, id: 29 }, + Colour { r: 0x00, g: 0x66, b: 0x66, a: 0xFF, id: 30 }, + Colour { r: 0x00, g: 0x66, b: 0x99, a: 0xFF, id: 31 }, + Colour { r: 0x00, g: 0x66, b: 0xCC, a: 0xFF, id: 32 }, + Colour { r: 0x00, g: 0x66, b: 0xFF, a: 0xFF, id: 33 }, + Colour { r: 0x00, g: 0x99, b: 0x00, a: 0xFF, id: 34 }, + Colour { r: 0x00, g: 0x99, b: 0x33, a: 0xFF, id: 35 }, + Colour { r: 0x00, g: 0x99, b: 0x66, a: 0xFF, id: 36 }, + Colour { r: 0x00, g: 0x99, b: 0x99, a: 0xFF, id: 37 }, + Colour { r: 0x00, g: 0x99, b: 0xCC, a: 0xFF, id: 38 }, + Colour { r: 0x00, g: 0x99, b: 0xFF, a: 0xFF, id: 39 }, + Colour { r: 0x00, g: 0xCC, b: 0x00, a: 0xFF, id: 40 }, + Colour { r: 0x00, g: 0xCC, b: 0x33, a: 0xFF, id: 41 }, + Colour { r: 0x00, g: 0xCC, b: 0x66, a: 0xFF, id: 42 }, + Colour { r: 0x00, g: 0xCC, b: 0x99, a: 0xFF, id: 43 }, + Colour { r: 0x00, g: 0xCC, b: 0xCC, a: 0xFF, id: 44 }, + Colour { r: 0x00, g: 0xCC, b: 0xFF, a: 0xFF, id: 45 }, + Colour { r: 0x00, g: 0xFF, b: 0x00, a: 0xFF, id: 46 }, + Colour { r: 0x00, g: 0xFF, b: 0x33, a: 0xFF, id: 47 }, + Colour { r: 0x00, g: 0xFF, b: 0x66, a: 0xFF, id: 48 }, + Colour { r: 0x00, g: 0xFF, b: 0x99, a: 0xFF, id: 49 }, + Colour { r: 0x00, g: 0xFF, b: 0xCC, a: 0xFF, id: 50 }, + Colour { r: 0x00, g: 0xFF, b: 0xFF, a: 0xFF, id: 51 }, + Colour { r: 0x33, g: 0x00, b: 0x00, a: 0xFF, id: 52 }, + Colour { r: 0x33, g: 0x00, b: 0x33, a: 0xFF, id: 53 }, + Colour { r: 0x33, g: 0x00, b: 0x66, a: 0xFF, id: 54 }, + Colour { r: 0x33, g: 0x00, b: 0x99, a: 0xFF, id: 55 }, + Colour { r: 0x33, g: 0x00, b: 0xCC, a: 0xFF, id: 56 }, + Colour { r: 0x33, g: 0x00, b: 0xFF, a: 0xFF, id: 57 }, + Colour { r: 0x33, g: 0x33, b: 0x00, a: 0xFF, id: 58 }, + Colour { r: 0x33, g: 0x33, b: 0x33, a: 0xFF, id: 59 }, + Colour { r: 0x33, g: 0x33, b: 0x66, a: 0xFF, id: 60 }, + Colour { r: 0x33, g: 0x33, b: 0x99, a: 0xFF, id: 61 }, + Colour { r: 0x33, g: 0x33, b: 0xCC, a: 0xFF, id: 62 }, + Colour { r: 0x33, g: 0x33, b: 0xFF, a: 0xFF, id: 63 }, + Colour { r: 0x33, g: 0x66, b: 0x00, a: 0xFF, id: 64 }, + Colour { r: 0x33, g: 0x66, b: 0x33, a: 0xFF, id: 65 }, + Colour { r: 0x33, g: 0x66, b: 0x66, a: 0xFF, id: 66 }, + Colour { r: 0x33, g: 0x66, b: 0x99, a: 0xFF, id: 67 }, + Colour { r: 0x33, g: 0x66, b: 0xCC, a: 0xFF, id: 68 }, + Colour { r: 0x33, g: 0x66, b: 0xFF, a: 0xFF, id: 69 }, + Colour { r: 0x33, g: 0x99, b: 0x00, a: 0xFF, id: 70 }, + Colour { r: 0x33, g: 0x99, b: 0x33, a: 0xFF, id: 71 }, + Colour { r: 0x33, g: 0x99, b: 0x66, a: 0xFF, id: 72 }, + Colour { r: 0x33, g: 0x99, b: 0x99, a: 0xFF, id: 73 }, + Colour { r: 0x33, g: 0x99, b: 0xCC, a: 0xFF, id: 74 }, + Colour { r: 0x33, g: 0x99, b: 0xFF, a: 0xFF, id: 75 }, + Colour { r: 0x33, g: 0xCC, b: 0x00, a: 0xFF, id: 76 }, + Colour { r: 0x33, g: 0xCC, b: 0x33, a: 0xFF, id: 77 }, + Colour { r: 0x33, g: 0xCC, b: 0x66, a: 0xFF, id: 78 }, + Colour { r: 0x33, g: 0xCC, b: 0x99, a: 0xFF, id: 79 }, + Colour { r: 0x33, g: 0xCC, b: 0xCC, a: 0xFF, id: 80 }, + Colour { r: 0x33, g: 0xCC, b: 0xFF, a: 0xFF, id: 81 }, + Colour { r: 0x33, g: 0xFF, b: 0x00, a: 0xFF, id: 82 }, + Colour { r: 0x33, g: 0xFF, b: 0x33, a: 0xFF, id: 83 }, + Colour { r: 0x33, g: 0xFF, b: 0x66, a: 0xFF, id: 84 }, + Colour { r: 0x33, g: 0xFF, b: 0x99, a: 0xFF, id: 85 }, + Colour { r: 0x33, g: 0xFF, b: 0xCC, a: 0xFF, id: 86 }, + Colour { r: 0x33, g: 0xFF, b: 0xFF, a: 0xFF, id: 87 }, + Colour { r: 0x66, g: 0x00, b: 0x00, a: 0xFF, id: 88 }, + Colour { r: 0x66, g: 0x00, b: 0x33, a: 0xFF, id: 89 }, + Colour { r: 0x66, g: 0x00, b: 0x66, a: 0xFF, id: 90 }, + Colour { r: 0x66, g: 0x00, b: 0x99, a: 0xFF, id: 91 }, + Colour { r: 0x66, g: 0x00, b: 0xCC, a: 0xFF, id: 92 }, + Colour { r: 0x66, g: 0x00, b: 0xFF, a: 0xFF, id: 93 }, + Colour { r: 0x66, g: 0x33, b: 0x00, a: 0xFF, id: 94 }, + Colour { r: 0x66, g: 0x33, b: 0x33, a: 0xFF, id: 95 }, + Colour { r: 0x66, g: 0x33, b: 0x66, a: 0xFF, id: 96 }, + Colour { r: 0x66, g: 0x33, b: 0x99, a: 0xFF, id: 97 }, + Colour { r: 0x66, g: 0x33, b: 0xCC, a: 0xFF, id: 98 }, + Colour { r: 0x66, g: 0x33, b: 0xFF, a: 0xFF, id: 99 }, + Colour { r: 0x66, g: 0x66, b: 0x00, a: 0xFF, id: 100 }, + Colour { r: 0x66, g: 0x66, b: 0x33, a: 0xFF, id: 101 }, + Colour { r: 0x66, g: 0x66, b: 0x66, a: 0xFF, id: 102 }, + Colour { r: 0x66, g: 0x66, b: 0x99, a: 0xFF, id: 103 }, + Colour { r: 0x66, g: 0x66, b: 0xCC, a: 0xFF, id: 104 }, + Colour { r: 0x66, g: 0x66, b: 0xFF, a: 0xFF, id: 105 }, + Colour { r: 0x66, g: 0x99, b: 0x00, a: 0xFF, id: 106 }, + Colour { r: 0x66, g: 0x99, b: 0x33, a: 0xFF, id: 107 }, + Colour { r: 0x66, g: 0x99, b: 0x66, a: 0xFF, id: 108 }, + Colour { r: 0x66, g: 0x99, b: 0x99, a: 0xFF, id: 109 }, + Colour { r: 0x66, g: 0x99, b: 0xCC, a: 0xFF, id: 110 }, + Colour { r: 0x66, g: 0x99, b: 0xFF, a: 0xFF, id: 111 }, + Colour { r: 0x66, g: 0xCC, b: 0x00, a: 0xFF, id: 112 }, + Colour { r: 0x66, g: 0xCC, b: 0x33, a: 0xFF, id: 113 }, + Colour { r: 0x66, g: 0xCC, b: 0x66, a: 0xFF, id: 114 }, + Colour { r: 0x66, g: 0xCC, b: 0x99, a: 0xFF, id: 115 }, + Colour { r: 0x66, g: 0xCC, b: 0xCC, a: 0xFF, id: 116 }, + Colour { r: 0x66, g: 0xCC, b: 0xFF, a: 0xFF, id: 117 }, + Colour { r: 0x66, g: 0xFF, b: 0x00, a: 0xFF, id: 118 }, + Colour { r: 0x66, g: 0xFF, b: 0x33, a: 0xFF, id: 119 }, + Colour { r: 0x66, g: 0xFF, b: 0x66, a: 0xFF, id: 120 }, + Colour { r: 0x66, g: 0xFF, b: 0x99, a: 0xFF, id: 121 }, + Colour { r: 0x66, g: 0xFF, b: 0xCC, a: 0xFF, id: 122 }, + Colour { r: 0x66, g: 0xFF, b: 0xFF, a: 0xFF, id: 123 }, + Colour { r: 0x99, g: 0x00, b: 0x00, a: 0xFF, id: 124 }, + Colour { r: 0x99, g: 0x00, b: 0x33, a: 0xFF, id: 125 }, + Colour { r: 0x99, g: 0x00, b: 0x66, a: 0xFF, id: 126 }, + Colour { r: 0x99, g: 0x00, b: 0x99, a: 0xFF, id: 127 }, + Colour { r: 0x99, g: 0x00, b: 0xCC, a: 0xFF, id: 128 }, + Colour { r: 0x99, g: 0x00, b: 0xFF, a: 0xFF, id: 129 }, + Colour { r: 0x99, g: 0x33, b: 0x00, a: 0xFF, id: 130 }, + Colour { r: 0x99, g: 0x33, b: 0x33, a: 0xFF, id: 131 }, + Colour { r: 0x99, g: 0x33, b: 0x66, a: 0xFF, id: 132 }, + Colour { r: 0x99, g: 0x33, b: 0x99, a: 0xFF, id: 133 }, + Colour { r: 0x99, g: 0x33, b: 0xCC, a: 0xFF, id: 134 }, + Colour { r: 0x99, g: 0x33, b: 0xFF, a: 0xFF, id: 135 }, + Colour { r: 0x99, g: 0x66, b: 0x00, a: 0xFF, id: 136 }, + Colour { r: 0x99, g: 0x66, b: 0x33, a: 0xFF, id: 137 }, + Colour { r: 0x99, g: 0x66, b: 0x66, a: 0xFF, id: 138 }, + Colour { r: 0x99, g: 0x66, b: 0x99, a: 0xFF, id: 139 }, + Colour { r: 0x99, g: 0x66, b: 0xCC, a: 0xFF, id: 140 }, + Colour { r: 0x99, g: 0x66, b: 0xFF, a: 0xFF, id: 141 }, + Colour { r: 0x99, g: 0x99, b: 0x00, a: 0xFF, id: 142 }, + Colour { r: 0x99, g: 0x99, b: 0x33, a: 0xFF, id: 143 }, + Colour { r: 0x99, g: 0x99, b: 0x66, a: 0xFF, id: 144 }, + Colour { r: 0x99, g: 0x99, b: 0x99, a: 0xFF, id: 145 }, + Colour { r: 0x99, g: 0x99, b: 0xCC, a: 0xFF, id: 146 }, + Colour { r: 0x99, g: 0x99, b: 0xFF, a: 0xFF, id: 147 }, + Colour { r: 0x99, g: 0xCC, b: 0x00, a: 0xFF, id: 148 }, + Colour { r: 0x99, g: 0xCC, b: 0x33, a: 0xFF, id: 149 }, + Colour { r: 0x99, g: 0xCC, b: 0x66, a: 0xFF, id: 150 }, + Colour { r: 0x99, g: 0xCC, b: 0x99, a: 0xFF, id: 151 }, + Colour { r: 0x99, g: 0xCC, b: 0xCC, a: 0xFF, id: 152 }, + Colour { r: 0x99, g: 0xCC, b: 0xFF, a: 0xFF, id: 153 }, + Colour { r: 0x99, g: 0xFF, b: 0x00, a: 0xFF, id: 154 }, + Colour { r: 0x99, g: 0xFF, b: 0x33, a: 0xFF, id: 155 }, + Colour { r: 0x99, g: 0xFF, b: 0x66, a: 0xFF, id: 156 }, + Colour { r: 0x99, g: 0xFF, b: 0x99, a: 0xFF, id: 157 }, + Colour { r: 0x99, g: 0xFF, b: 0xCC, a: 0xFF, id: 158 }, + Colour { r: 0x99, g: 0xFF, b: 0xFF, a: 0xFF, id: 159 }, + Colour { r: 0xCC, g: 0x00, b: 0x00, a: 0xFF, id: 160 }, + Colour { r: 0xCC, g: 0x00, b: 0x33, a: 0xFF, id: 161 }, + Colour { r: 0xCC, g: 0x00, b: 0x66, a: 0xFF, id: 162 }, + Colour { r: 0xCC, g: 0x00, b: 0x99, a: 0xFF, id: 163 }, + Colour { r: 0xCC, g: 0x00, b: 0xCC, a: 0xFF, id: 164 }, + Colour { r: 0xCC, g: 0x00, b: 0xFF, a: 0xFF, id: 165 }, + Colour { r: 0xCC, g: 0x33, b: 0x00, a: 0xFF, id: 166 }, + Colour { r: 0xCC, g: 0x33, b: 0x33, a: 0xFF, id: 167 }, + Colour { r: 0xCC, g: 0x33, b: 0x66, a: 0xFF, id: 168 }, + Colour { r: 0xCC, g: 0x33, b: 0x99, a: 0xFF, id: 169 }, + Colour { r: 0xCC, g: 0x33, b: 0xCC, a: 0xFF, id: 170 }, + Colour { r: 0xCC, g: 0x33, b: 0xFF, a: 0xFF, id: 171 }, + Colour { r: 0xCC, g: 0x66, b: 0x00, a: 0xFF, id: 172 }, + Colour { r: 0xCC, g: 0x66, b: 0x33, a: 0xFF, id: 173 }, + Colour { r: 0xCC, g: 0x66, b: 0x66, a: 0xFF, id: 174 }, + Colour { r: 0xCC, g: 0x66, b: 0x99, a: 0xFF, id: 175 }, + Colour { r: 0xCC, g: 0x66, b: 0xCC, a: 0xFF, id: 176 }, + Colour { r: 0xCC, g: 0x66, b: 0xFF, a: 0xFF, id: 177 }, + Colour { r: 0xCC, g: 0x99, b: 0x00, a: 0xFF, id: 178 }, + Colour { r: 0xCC, g: 0x99, b: 0x33, a: 0xFF, id: 179 }, + Colour { r: 0xCC, g: 0x99, b: 0x66, a: 0xFF, id: 180 }, + Colour { r: 0xCC, g: 0x99, b: 0x99, a: 0xFF, id: 181 }, + Colour { r: 0xCC, g: 0x99, b: 0xCC, a: 0xFF, id: 182 }, + Colour { r: 0xCC, g: 0x99, b: 0xFF, a: 0xFF, id: 183 }, + Colour { r: 0xCC, g: 0xCC, b: 0x00, a: 0xFF, id: 184 }, + Colour { r: 0xCC, g: 0xCC, b: 0x33, a: 0xFF, id: 185 }, + Colour { r: 0xCC, g: 0xCC, b: 0x66, a: 0xFF, id: 186 }, + Colour { r: 0xCC, g: 0xCC, b: 0x99, a: 0xFF, id: 187 }, + Colour { r: 0xCC, g: 0xCC, b: 0xCC, a: 0xFF, id: 188 }, + Colour { r: 0xCC, g: 0xCC, b: 0xFF, a: 0xFF, id: 189 }, + Colour { r: 0xCC, g: 0xFF, b: 0x00, a: 0xFF, id: 190 }, + Colour { r: 0xCC, g: 0xFF, b: 0x33, a: 0xFF, id: 191 }, + Colour { r: 0xCC, g: 0xFF, b: 0x66, a: 0xFF, id: 192 }, + Colour { r: 0xCC, g: 0xFF, b: 0x99, a: 0xFF, id: 193 }, + Colour { r: 0xCC, g: 0xFF, b: 0xCC, a: 0xFF, id: 194 }, + Colour { r: 0xCC, g: 0xFF, b: 0xFF, a: 0xFF, id: 195 }, + Colour { r: 0xFF, g: 0x00, b: 0x00, a: 0xFF, id: 196 }, + Colour { r: 0xFF, g: 0x00, b: 0x33, a: 0xFF, id: 197 }, + Colour { r: 0xFF, g: 0x00, b: 0x66, a: 0xFF, id: 198 }, + Colour { r: 0xFF, g: 0x00, b: 0x99, a: 0xFF, id: 199 }, + Colour { r: 0xFF, g: 0x00, b: 0xCC, a: 0xFF, id: 200 }, + Colour { r: 0xFF, g: 0x00, b: 0xFF, a: 0xFF, id: 201 }, + Colour { r: 0xFF, g: 0x33, b: 0x00, a: 0xFF, id: 202 }, + Colour { r: 0xFF, g: 0x33, b: 0x33, a: 0xFF, id: 203 }, + Colour { r: 0xFF, g: 0x33, b: 0x66, a: 0xFF, id: 204 }, + Colour { r: 0xFF, g: 0x33, b: 0x99, a: 0xFF, id: 205 }, + Colour { r: 0xFF, g: 0x33, b: 0xCC, a: 0xFF, id: 206 }, + Colour { r: 0xFF, g: 0x33, b: 0xFF, a: 0xFF, id: 207 }, + Colour { r: 0xFF, g: 0x66, b: 0x00, a: 0xFF, id: 208 }, + Colour { r: 0xFF, g: 0x66, b: 0x33, a: 0xFF, id: 209 }, + Colour { r: 0xFF, g: 0x66, b: 0x66, a: 0xFF, id: 210 }, + Colour { r: 0xFF, g: 0x66, b: 0x99, a: 0xFF, id: 211 }, + Colour { r: 0xFF, g: 0x66, b: 0xCC, a: 0xFF, id: 212 }, + Colour { r: 0xFF, g: 0x66, b: 0xFF, a: 0xFF, id: 213 }, + Colour { r: 0xFF, g: 0x99, b: 0x00, a: 0xFF, id: 214 }, + Colour { r: 0xFF, g: 0x99, b: 0x33, a: 0xFF, id: 215 }, + Colour { r: 0xFF, g: 0x99, b: 0x66, a: 0xFF, id: 216 }, + Colour { r: 0xFF, g: 0x99, b: 0x99, a: 0xFF, id: 217 }, + Colour { r: 0xFF, g: 0x99, b: 0xCC, a: 0xFF, id: 218 }, + Colour { r: 0xFF, g: 0x99, b: 0xFF, a: 0xFF, id: 219 }, + Colour { r: 0xFF, g: 0xCC, b: 0x00, a: 0xFF, id: 220 }, + Colour { r: 0xFF, g: 0xCC, b: 0x33, a: 0xFF, id: 221 }, + Colour { r: 0xFF, g: 0xCC, b: 0x66, a: 0xFF, id: 222 }, + Colour { r: 0xFF, g: 0xCC, b: 0x99, a: 0xFF, id: 223 }, + Colour { r: 0xFF, g: 0xCC, b: 0xCC, a: 0xFF, id: 224 }, + Colour { r: 0xFF, g: 0xCC, b: 0xFF, a: 0xFF, id: 225 }, + Colour { r: 0xFF, g: 0xFF, b: 0x00, a: 0xFF, id: 226 }, + Colour { r: 0xFF, g: 0xFF, b: 0x33, a: 0xFF, id: 227 }, + Colour { r: 0xFF, g: 0xFF, b: 0x66, a: 0xFF, id: 228 }, + Colour { r: 0xFF, g: 0xFF, b: 0x99, a: 0xFF, id: 229 }, + Colour { r: 0xFF, g: 0xFF, b: 0xCC, a: 0xFF, id: 230 }, + Colour { r: 0xFF, g: 0xFF, b: 0xFF, a: 0xFF, id: 231 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 232 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 233 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 234 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 235 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 236 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 237 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 238 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 239 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 240 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 241 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 242 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 243 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 244 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 245 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 246 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 247 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 248 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 249 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 250 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 251 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 252 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 253 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 254 }, + Colour { r: 0x00, g: 0x00, b: 0x00, a: 0xFF, id: 255 }, + ]; +} + +impl Default for Colour { + fn default() -> Self { + Colour::GREY + } +} + +impl From for Colour { + fn from(color_id: u8) -> Self { + Colour::new_by_id(color_id) + } +} + +impl From for u8 { + fn from(color: Colour) -> Self { + color.id + } +} + +impl From for Colour { + fn from(val: u32) -> Self { + let b = val.to_le_bytes(); + Colour::new_by_rgba(b[0], b[1], b[2], b[3]) + } +} diff --git a/src/object_pool/mod.rs b/src/object_pool/mod.rs new file mode 100644 index 0000000..c12c414 --- /dev/null +++ b/src/object_pool/mod.rs @@ -0,0 +1,22 @@ +pub mod colour; +pub mod reader; +pub mod writer; + +mod object; +mod object_attributes; +mod object_id; +mod object_pool; +mod object_type; +mod vt_version; + +use crate::network_management::name::NAME; + +pub use colour::Colour; +pub use object_pool::ObjectPool; +pub use object_type::ObjectType; + +#[derive(Debug)] +pub enum ParseError { + DataEmpty, + UnknownObjectType, +} diff --git a/src/object_pool/object.rs b/src/object_pool/object.rs new file mode 100644 index 0000000..39bdb66 --- /dev/null +++ b/src/object_pool/object.rs @@ -0,0 +1,742 @@ +use crate::network_management::name::NAME; +use crate::object_pool::object_attributes::{ + Alignment, AnimationOptions, ButtonOptions, ColorFormat, ColourPaletteOptions, + ExternalObjectDefinitionOptions, ExternalReferenceNameOptions, FormatType, + GraphicsContextOptions, InputListOptions, InputNumberOptions, InputStringOptions, + KeyGroupOptions, LineDirection, MacroRef, NumberOptions, ObjectLabel, ObjectRef, + OutputArchedBarGraphOptions, OutputLinearBarGraphOptions, OutputMeterOptions, + OutputStringOptions, PictureGraphicOptions, Point, ScaledGraphicOptions, WindowMaskCellFormat, + WindowMaskOptions, WindowType, +}; +use crate::object_pool::object_id::ObjectId; +use crate::object_pool::{Colour, ObjectType}; + +#[derive(Debug)] +pub enum Object { + WorkingSet(WorkingSet), + DataMask(DataMask), + AlarmMask(AlarmMask), + Container(Container), + SoftKeyMask(SoftKeyMask), + Key(Key), + Button(Button), + InputBoolean(InputBoolean), + InputString(InputString), + InputNumber(InputNumber), + InputList(InputList), + OutputString(OutputString), + OutputNumber(OutputNumber), + OutputLine(OutputLine), + OutputRectangle(OutputRectangle), + OutputEllipse(OutputEllipse), + OutputPolygon(OutputPolygon), + OutputMeter(OutputMeter), + OutputLinearBarGraph(OutputLinearBarGraph), + OutputArchedBarGraph(OutputArchedBarGraph), + PictureGraphic(PictureGraphic), + NumberVariable(NumberVariable), + StringVariable(StringVariable), + FontAttributes(FontAttributes), + LineAttributes(LineAttributes), + FillAttributes(FillAttributes), + InputAttributes(InputAttributes), + ObjectPointer(ObjectPointer), + Macro(Macro), + AuxiliaryFunctionType1(AuxiliaryFunctionType1), + AuxiliaryInputType1(AuxiliaryInputType1), + AuxiliaryFunctionType2(AuxiliaryFunctionType2), + AuxiliaryInputType2(AuxiliaryInputType2), + AuxiliaryControlDesignatorType2(AuxiliaryControlDesignatorType2), + WindowMask(WindowMask), + KeyGroup(KeyGroup), + GraphicsContext(GraphicsContext), + OutputList(OutputList), + ExtendedInputAttributes(ExtendedInputAttributes), + ColourMap(ColourMap), + ObjectLabelReferenceList(ObjectLabelReferenceList), + ExternalObjectDefinition(ExternalObjectDefinition), + ExternalReferenceName(ExternalReferenceName), + ExternalObjectPointer(ExternalObjectPointer), + Animation(Animation), + ColourPalette(ColourPalette), + GraphicData(GraphicData), + WorkingSetSpecialControls(WorkingSetSpecialControls), + ScaledGraphic(ScaledGraphic), +} + +impl Object { + pub fn id(&self) -> ObjectId { + match self { + Object::WorkingSet(o) => o.id, + Object::DataMask(o) => o.id, + Object::AlarmMask(o) => o.id, + Object::Container(o) => o.id, + Object::SoftKeyMask(o) => o.id, + Object::Key(o) => o.id, + Object::Button(o) => o.id, + Object::InputBoolean(o) => o.id, + Object::InputString(o) => o.id, + Object::InputNumber(o) => o.id, + Object::InputList(o) => o.id, + Object::OutputString(o) => o.id, + Object::OutputNumber(o) => o.id, + Object::OutputLine(o) => o.id, + Object::OutputRectangle(o) => o.id, + Object::OutputEllipse(o) => o.id, + Object::OutputPolygon(o) => o.id, + Object::OutputMeter(o) => o.id, + Object::OutputLinearBarGraph(o) => o.id, + Object::OutputArchedBarGraph(o) => o.id, + Object::PictureGraphic(o) => o.id, + Object::NumberVariable(o) => o.id, + Object::StringVariable(o) => o.id, + Object::FontAttributes(o) => o.id, + Object::LineAttributes(o) => o.id, + Object::FillAttributes(o) => o.id, + Object::InputAttributes(o) => o.id, + Object::ObjectPointer(o) => o.id, + Object::Macro(o) => o.id, + Object::AuxiliaryFunctionType1(o) => o.id, + Object::AuxiliaryInputType1(o) => o.id, + Object::AuxiliaryFunctionType2(o) => o.id, + Object::AuxiliaryInputType2(o) => o.id, + Object::AuxiliaryControlDesignatorType2(o) => o.id, + Object::WindowMask(o) => o.id, + Object::KeyGroup(o) => o.id, + Object::GraphicsContext(o) => o.id, + Object::OutputList(o) => o.id, + Object::ExtendedInputAttributes(o) => o.id, + Object::ColourMap(o) => o.id, + Object::ObjectLabelReferenceList(o) => o.id, + Object::ExternalObjectDefinition(o) => o.id, + Object::ExternalReferenceName(o) => o.id, + Object::ExternalObjectPointer(o) => o.id, + Object::Animation(o) => o.id, + Object::ColourPalette(o) => o.id, + Object::GraphicData(o) => o.id, + Object::WorkingSetSpecialControls(o) => o.id, + Object::ScaledGraphic(o) => o.id, + } + } + + pub fn object_type(&self) -> ObjectType { + match self { + Object::WorkingSet(_) => ObjectType::WorkingSet, + Object::DataMask(_) => ObjectType::DataMask, + Object::AlarmMask(_) => ObjectType::AlarmMask, + Object::Container(_) => ObjectType::Container, + Object::SoftKeyMask(_) => ObjectType::SoftKeyMask, + Object::Key(_) => ObjectType::Key, + Object::Button(_) => ObjectType::Button, + Object::InputBoolean(_) => ObjectType::InputBoolean, + Object::InputString(_) => ObjectType::InputString, + Object::InputNumber(_) => ObjectType::InputNumber, + Object::InputList(_) => ObjectType::InputList, + Object::OutputString(_) => ObjectType::OutputString, + Object::OutputNumber(_) => ObjectType::OutputNumber, + Object::OutputLine(_) => ObjectType::OutputLine, + Object::OutputRectangle(_) => ObjectType::OutputRectangle, + Object::OutputEllipse(_) => ObjectType::OutputEllipse, + Object::OutputPolygon(_) => ObjectType::OutputPolygon, + Object::OutputMeter(_) => ObjectType::OutputMeter, + Object::OutputLinearBarGraph(_) => ObjectType::OutputLinearBarGraph, + Object::OutputArchedBarGraph(_) => ObjectType::OutputArchedBarGraph, + Object::PictureGraphic(_) => ObjectType::PictureGraphic, + Object::NumberVariable(_) => ObjectType::NumberVariable, + Object::StringVariable(_) => ObjectType::StringVariable, + Object::FontAttributes(_) => ObjectType::FontAttributes, + Object::LineAttributes(_) => ObjectType::LineAttributes, + Object::FillAttributes(_) => ObjectType::FillAttributes, + Object::InputAttributes(_) => ObjectType::InputAttributes, + Object::ObjectPointer(_) => ObjectType::ObjectPointer, + Object::Macro(_) => ObjectType::Macro, + Object::AuxiliaryFunctionType1(_) => ObjectType::AuxiliaryFunctionType1, + Object::AuxiliaryInputType1(_) => ObjectType::AuxiliaryInputType1, + Object::AuxiliaryFunctionType2(_) => ObjectType::AuxiliaryFunctionType2, + Object::AuxiliaryInputType2(_) => ObjectType::AuxiliaryInputType2, + Object::AuxiliaryControlDesignatorType2(_) => { + ObjectType::AuxiliaryControlDesignatorType2 + } + Object::WindowMask(_) => ObjectType::WindowMask, + Object::KeyGroup(_) => ObjectType::KeyGroup, + Object::GraphicsContext(_) => ObjectType::GraphicsContext, + Object::OutputList(_) => ObjectType::OutputList, + Object::ExtendedInputAttributes(_) => ObjectType::ExtendedInputAttributes, + Object::ColourMap(_) => ObjectType::ColourMap, + Object::ObjectLabelReferenceList(_) => ObjectType::ObjectLabelReferenceList, + Object::ExternalObjectDefinition(_) => ObjectType::ExternalObjectDefinition, + Object::ExternalReferenceName(_) => ObjectType::ExternalReferenceName, + Object::ExternalObjectPointer(_) => ObjectType::ExternalObjectPointer, + Object::Animation(_) => ObjectType::Animation, + Object::ColourPalette(_) => ObjectType::ColourPalette, + Object::GraphicData(_) => ObjectType::GraphicData, + Object::WorkingSetSpecialControls(_) => ObjectType::WorkingSetSpecialControls, + Object::ScaledGraphic(_) => ObjectType::ScaledGraphic, + } + } +} + +#[derive(Debug, PartialEq)] +pub struct WorkingSet { + pub id: ObjectId, + pub background_colour: Colour, + pub selectable: bool, + pub active_mask: ObjectId, + pub object_refs: Vec, + pub macro_refs: Vec, + pub language_codes: Vec, +} + +#[derive(Debug, PartialEq)] +pub struct DataMask { + pub id: ObjectId, + pub background_colour: u8, + pub soft_key_mask: ObjectId, + pub object_refs: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug, PartialEq)] +pub struct AlarmMask { + pub id: ObjectId, + pub background_colour: u8, + pub soft_key_mask: ObjectId, + pub priority: u8, + pub acoustic_signal: u8, + pub object_refs: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug, PartialEq)] +pub struct Container { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub hidden: bool, + pub object_refs: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug, PartialEq)] +pub struct SoftKeyMask { + pub id: ObjectId, + pub background_colour: u8, + pub objects: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug, PartialEq)] +pub struct Key { + pub id: ObjectId, + pub background_colour: u8, + pub key_code: u8, + pub object_refs: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug, PartialEq)] +pub struct Button { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub background_colour: u8, + pub border_colour: u8, + pub key_code: u8, + pub options: ButtonOptions, + pub object_refs: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug, PartialEq)] +pub struct InputBoolean { + pub id: ObjectId, + pub background_colour: u8, + pub width: u16, + pub foreground_colour: ObjectId, + pub variable_reference: ObjectId, + pub value: bool, + pub enabled: bool, + pub macro_refs: Vec, +} + +#[derive(Debug, PartialEq)] +pub struct InputString { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub background_colour: u8, + pub font_attributes: ObjectId, + pub input_attributes: ObjectId, + pub options: InputStringOptions, + pub variable_reference: ObjectId, + pub justification: Alignment, + pub value: String, + pub enabled: bool, + pub macro_refs: Vec, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct InputNumber { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub background_colour: u8, + pub font_attributes: ObjectId, + pub options: NumberOptions, + pub variable_reference: ObjectId, + pub value: u32, + pub min_value: u32, + pub max_value: u32, + pub offset: i32, + pub scale: f32, + pub nr_of_decimals: u8, + pub format: FormatType, + pub justification: Alignment, + pub options2: InputNumberOptions, + pub macro_refs: Vec, +} + +#[derive(Debug, PartialEq, Clone)] +pub struct InputList { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub variable_reference: ObjectId, + pub value: u8, + pub options: InputListOptions, + pub list_items: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug, PartialEq, Clone)] +pub struct OutputString { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub background_colour: u8, + pub font_attributes: ObjectId, + pub options: OutputStringOptions, + pub variable_reference: ObjectId, + pub justification: Alignment, + pub value: String, + pub macro_refs: Vec, +} + +#[derive(Debug, PartialEq)] +pub struct OutputNumber { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub background_colour: u8, + pub font_attributes: ObjectId, + pub options: NumberOptions, + pub variable_reference: ObjectId, + pub value: u32, + pub offset: i32, + pub scale: f32, + pub nr_of_decimals: u8, + pub format: FormatType, + pub justification: Alignment, + pub macro_refs: Vec, +} + +#[derive(Debug, PartialEq, Clone)] +pub struct OutputList { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub variable_reference: ObjectId, + pub value: u8, + pub list_items: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug, PartialEq, Clone)] +pub struct OutputLine { + pub id: ObjectId, + pub line_attributes: ObjectId, + pub width: u16, + pub height: u16, + pub line_direction: LineDirection, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct OutputRectangle { + pub id: ObjectId, + pub line_attributes: ObjectId, + pub width: u16, + pub height: u16, + pub line_suppression: u8, + pub fill_attributes: ObjectId, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct OutputEllipse { + pub id: ObjectId, + pub line_attributes: ObjectId, + pub width: u16, + pub height: u16, + pub ellipse_type: u8, + pub start_angle: u8, + pub end_angle: u8, + pub fill_attributes: ObjectId, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct OutputPolygon { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub line_attributes: ObjectId, + pub fill_attributes: ObjectId, + pub polygon_type: u8, + pub points: Vec>, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct OutputMeter { + pub id: ObjectId, + pub width: u16, + pub needle_colour: u8, + pub border_colour: u8, + pub arc_and_tick_colour: u8, + pub options: OutputMeterOptions, + pub nr_of_ticks: u8, + pub start_angle: u8, + pub end_angle: u8, + pub min_value: u16, + pub max_value: u16, + pub variable_reference: ObjectId, + pub value: u16, + pub macro_refs: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct OutputLinearBarGraph { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub colour: u8, + pub target_line_colour: u8, + pub options: OutputLinearBarGraphOptions, + pub nr_of_ticks: u8, + pub min_value: u16, + pub max_value: u16, + pub variable_reference: ObjectId, + pub value: u16, + pub target_value_variable_reference: ObjectId, + pub target_value: u16, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct OutputArchedBarGraph { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub colour: u8, + pub target_line_colour: u8, + pub options: OutputArchedBarGraphOptions, + pub start_angle: u8, + pub end_angle: u8, + pub bar_graph_width: u16, + pub min_value: u16, + pub max_value: u16, + pub variable_reference: ObjectId, + pub value: u16, + pub target_value_variable_reference: ObjectId, + pub target_value: u16, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct PictureGraphic { + pub id: ObjectId, + pub width: u16, + pub actual_width: u16, + pub actual_height: u16, + pub format: u8, + pub options: PictureGraphicOptions, + pub transparency_colour: u8, + pub data: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct NumberVariable { + pub id: ObjectId, + pub value: u32, +} + +#[derive(Debug)] +pub struct StringVariable { + pub id: ObjectId, + pub value: String, +} + +#[derive(Debug)] +pub struct FontAttributes { + pub id: ObjectId, + pub font_colour: u8, + pub font_size: u8, + pub font_type: u8, + pub font_style: u8, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct LineAttributes { + pub id: ObjectId, + pub line_colour: u8, + pub line_width: u8, + pub line_art: u16, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct FillAttributes { + pub id: ObjectId, + pub fill_type: u8, + pub fill_colour: u8, + pub fill_pattern: ObjectId, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct InputAttributes { + pub id: ObjectId, + pub validation_type: u8, + pub validation_string: String, + pub macro_refs: Vec, +} + +#[derive(Debug, Copy, Clone)] +pub enum ValidationType { + ValidCharacters, + InvalidCharacters, +} + +impl From for u8 { + fn from(value: ValidationType) -> Self { + match value { + ValidationType::ValidCharacters => 0, + ValidationType::InvalidCharacters => 1, + } + } +} + +impl From for ValidationType { + fn from(value: u8) -> Self { + match value { + 0 => ValidationType::ValidCharacters, + 1 => ValidationType::InvalidCharacters, + _ => panic!("Invalid validation type"), + } + } +} + +#[derive(Debug)] +pub struct CharacterRange { + pub first_character: u16, + pub last_character: u16, +} + +#[derive(Debug)] +pub struct CodePlane { + pub number: u8, + pub character_ranges: Vec, +} + +#[derive(Debug)] +pub struct ExtendedInputAttributes { + pub id: ObjectId, + pub validation_type: ValidationType, + pub code_planes: Vec, +} + +#[derive(Debug)] +pub struct ObjectPointer { + pub id: ObjectId, + pub value: ObjectId, +} + +#[derive(Debug)] +pub struct Macro { + pub id: ObjectId, + pub commands: Vec, +} + +#[derive(Debug)] +pub struct AuxiliaryFunctionType1 { + pub id: ObjectId, + pub background_colour: u8, + pub function_type: u8, + pub object_refs: Vec, +} + +#[derive(Debug)] +pub struct AuxiliaryInputType1 { + pub id: ObjectId, + pub background_colour: u8, + pub function_type: u8, + pub input_id: u8, + pub object_refs: Vec, +} + +#[derive(Debug)] +pub struct AuxiliaryFunctionType2 { + pub id: ObjectId, + pub background_colour: u8, + pub function_attributes: u8, + pub object_refs: Vec, +} + +#[derive(Debug)] +pub struct AuxiliaryInputType2 { + pub id: ObjectId, + pub background_colour: u8, + pub function_attributes: u8, + pub object_refs: Vec, +} + +#[derive(Debug)] +pub struct AuxiliaryControlDesignatorType2 { + pub id: ObjectId, + pub pointer_type: u8, + pub auxiliary_object_id: ObjectId, +} + +#[derive(Debug)] +pub struct ColourMap { + pub id: ObjectId, + pub colour_map: Vec, +} + +#[derive(Debug, PartialEq, Copy, Clone)] +pub struct GraphicsContext { + pub id: ObjectId, + pub viewport_width: u16, + pub viewport_height: u16, + pub viewport_x: i16, + pub viewport_y: i16, + pub canvas_width: u16, + pub canvas_height: u16, + pub viewport_zoom: f32, + pub graphics_cursor_x: i16, + pub graphics_cursor_y: i16, + pub foreground_colour: u8, + pub background_colour: u8, + pub font_attributes_object: ObjectId, + pub line_attributes_object: ObjectId, + pub fill_attributes_object: ObjectId, + pub format: ColorFormat, + pub options: GraphicsContextOptions, + pub transparency_colour: u8, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct WindowMask { + pub id: ObjectId, + pub cell_format: WindowMaskCellFormat, + pub window_type: WindowType, + pub background_colour: u8, + pub options: WindowMaskOptions, + pub name: ObjectId, + pub window_title: ObjectId, + pub window_icon: ObjectId, + pub objects: Vec, + pub object_refs: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct KeyGroup { + pub id: ObjectId, + pub options: KeyGroupOptions, + pub name: ObjectId, + pub key_group_icon: ObjectId, + pub objects: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct ObjectLabelReferenceList { + pub id: ObjectId, + pub object_labels: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ExternalObjectDefinition { + pub id: ObjectId, + pub options: ExternalObjectDefinitionOptions, + pub name: NAME, + pub objects: Vec, +} + +#[derive(Debug)] +pub struct ExternalReferenceName { + pub id: ObjectId, + pub options: ExternalReferenceNameOptions, + pub name: NAME, +} + +#[derive(Debug)] +pub struct ExternalObjectPointer { + pub id: ObjectId, + pub default_object_id: ObjectId, + pub external_reference_name_id: ObjectId, + pub external_object_id: ObjectId, +} + +#[derive(Debug)] +pub struct Animation { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub refresh_interval: u16, + pub value: u8, + pub enabled: bool, + pub first_child_index: u8, + pub last_child_index: u8, + pub default_child_index: u8, + pub options: AnimationOptions, + pub object_refs: Vec, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct ColourPalette { + pub id: ObjectId, + pub options: ColourPaletteOptions, + pub colours: Vec, +} + +#[derive(Debug)] +pub struct GraphicData { + pub id: ObjectId, + pub format: u8, + pub data: Vec, +} + +#[derive(Debug)] +pub struct ScaledGraphic { + pub id: ObjectId, + pub width: u16, + pub height: u16, + pub scale_type: u8, + pub options: ScaledGraphicOptions, + pub value: u16, + pub macro_refs: Vec, +} + +#[derive(Debug)] +pub struct WorkingSetSpecialControls { + pub id: ObjectId, + pub id_of_colour_map: ObjectId, + pub id_of_colour_palette: ObjectId, + pub language_pairs: Vec<(String, String)>, +} diff --git a/src/object_pool/object_attributes.rs b/src/object_pool/object_attributes.rs new file mode 100644 index 0000000..3be6550 --- /dev/null +++ b/src/object_pool/object_attributes.rs @@ -0,0 +1,1068 @@ +use crate::object_pool::object_id::ObjectId; +use bitvec::field::BitField; +use bitvec::order::{Lsb0, Msb0}; +use bitvec::vec::BitVec; +use bitvec::view::BitView; +use strum_macros::FromRepr; + +#[derive(FromRepr, Debug, PartialEq, Clone, Copy)] +#[repr(u8)] +pub enum WindowType { + FreeForm = 0, + NumericOutputValueWithUnits1x1 = 1, + NumericOutputValueNoUnits1x1 = 2, + StringOutputValue1x1 = 3, + NumericInputValueWithUnits1x1 = 4, + NumericInputValueNoUnits1x1 = 5, + StringInputValue1x1 = 6, + HorizontalLinearBarGraph1x1 = 7, + SingleButton1x1 = 8, + DoubleButton1x1 = 9, + NumericOutputValueWithUnits2x1 = 10, + NumericOutputValueNoUnits2x1 = 11, + StringOutputValue2x1 = 12, + NumericInputValueWithUnits2x1 = 13, + NumericInputValueNoUnits2x1 = 14, + StringInputValue2x1 = 15, + HorizontalLinearBarGraph2x1 = 16, + SingleButton2x1 = 17, + DoubleButton2x1 = 18, +} + +impl From for WindowType { + fn from(value: u8) -> Self { + WindowType::from_repr(value).unwrap() + } +} + +impl From for u8 { + fn from(value: WindowType) -> Self { + value.into() + } +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum WindowMaskCellFormat { + CF1x1, + CF1x2, + CF1x3, + CF1x4, + CF1x5, + CF1x6, + CF2x1, + CF2x2, + CF2x3, + CF2x4, + CF2x5, + CF2x6, +} + +impl WindowMaskCellFormat { + const fn from_size(x: u8, y: u8) -> WindowMaskCellFormat { + let size = Point { x, y }; + match size { + Point { x: 1, y: 1 } => WindowMaskCellFormat::CF1x1, + Point { x: 1, y: 2 } => WindowMaskCellFormat::CF1x2, + Point { x: 1, y: 3 } => WindowMaskCellFormat::CF1x3, + Point { x: 1, y: 4 } => WindowMaskCellFormat::CF1x4, + Point { x: 1, y: 5 } => WindowMaskCellFormat::CF1x5, + Point { x: 1, y: 6 } => WindowMaskCellFormat::CF1x6, + Point { x: 2, y: 1 } => WindowMaskCellFormat::CF2x1, + Point { x: 2, y: 2 } => WindowMaskCellFormat::CF2x2, + Point { x: 2, y: 3 } => WindowMaskCellFormat::CF2x3, + Point { x: 2, y: 4 } => WindowMaskCellFormat::CF2x4, + Point { x: 2, y: 5 } => WindowMaskCellFormat::CF2x5, + Point { x: 2, y: 6 } => WindowMaskCellFormat::CF2x6, + _ => WindowMaskCellFormat::CF1x1, + } + } + + pub const fn size(self) -> Point { + match self { + WindowMaskCellFormat::CF1x1 => Point { x: 1, y: 1 }, + WindowMaskCellFormat::CF1x2 => Point { x: 1, y: 2 }, + WindowMaskCellFormat::CF1x3 => Point { x: 1, y: 3 }, + WindowMaskCellFormat::CF1x4 => Point { x: 1, y: 4 }, + WindowMaskCellFormat::CF1x5 => Point { x: 1, y: 5 }, + WindowMaskCellFormat::CF1x6 => Point { x: 1, y: 6 }, + WindowMaskCellFormat::CF2x1 => Point { x: 2, y: 1 }, + WindowMaskCellFormat::CF2x2 => Point { x: 2, y: 2 }, + WindowMaskCellFormat::CF2x3 => Point { x: 2, y: 3 }, + WindowMaskCellFormat::CF2x4 => Point { x: 2, y: 4 }, + WindowMaskCellFormat::CF2x5 => Point { x: 2, y: 5 }, + WindowMaskCellFormat::CF2x6 => Point { x: 2, y: 6 }, + } + } +} + +impl From for WindowMaskCellFormat { + fn from(value: u16) -> Self { + WindowMaskCellFormat::from_size((value << 8) as u8, value as u8) + } +} + +impl From for u16 { + fn from(value: WindowMaskCellFormat) -> Self { + let size = value.size(); + ((size.x as u16) << 8) | size.y as u16 + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct WindowMaskOptions { + pub available: bool, + pub transparent: bool, +} + +impl From for WindowMaskOptions { + fn from(value: u8) -> Self { + let mut bit_data = value.view_bits::().to_bitvec(); + WindowMaskOptions { + available: bit_data.pop().unwrap(), + transparent: bit_data.pop().unwrap(), + } + } +} + +impl From for u8 { + fn from(value: WindowMaskOptions) -> u8 { + let mut bit_data: BitVec = BitVec::new(); + bit_data.push(value.available); + bit_data.push(value.transparent); + bit_data.extend([0; 6]); + bit_data.load::() + } +} + +#[derive(Debug, PartialEq, Clone)] +pub struct ObjectRef { + pub id: ObjectId, + pub offset: Point, + // pub x: i16, + // pub y: i16, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct MacroRef { + pub macro_id: u8, + pub event_id: u8, +} + +#[derive(Debug, Default, Clone, Copy, PartialEq)] +pub struct Point { + pub x: T, + pub y: T, +} + +impl core::ops::Add> for Point { + type Output = Point; + + fn add(self, rhs: Point) -> Self::Output { + Point { + x: (self.x as i16 + rhs.x) as u16, + y: (self.y as i16 + rhs.y) as u16, + } + } +} + +#[derive(Debug)] +pub struct ObjectLabel { + pub id: ObjectId, + pub string_variable_reference: ObjectId, + pub font_type: u8, + pub graphic_representation: ObjectId, +} + +#[derive(Debug, PartialEq, Clone, Copy)] +pub struct ButtonOptions { + pub latchable: bool, + pub state: ButtonState, + pub suppress_border: bool, + pub transparent_background: bool, + pub disabled: bool, + pub no_border: bool, +} + +impl From for ButtonOptions { + fn from(value: u8) -> Self { + let mut bit_data = value.view_bits::().to_bitvec(); + ButtonOptions { + latchable: bit_data.pop().unwrap(), + state: bit_data.pop().unwrap().into(), + suppress_border: bit_data.pop().unwrap(), + transparent_background: bit_data.pop().unwrap(), + disabled: bit_data.pop().unwrap(), + no_border: bit_data.pop().unwrap(), + } + } +} + +impl From for u8 { + fn from(value: ButtonOptions) -> u8 { + let mut bit_data: BitVec = BitVec::new(); + bit_data.push(value.latchable); + bit_data.push(value.state.into()); + bit_data.push(value.suppress_border); + bit_data.push(value.transparent_background); + bit_data.push(value.disabled); + bit_data.push(value.no_border); + bit_data.extend([0; 3]); + bit_data.load::() + } +} + +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum ButtonState { + Released, + Latched, +} + +impl From for bool { + fn from(value: ButtonState) -> Self { + match value { + ButtonState::Released => false, + ButtonState::Latched => true, + } + } +} + +impl From for ButtonState { + fn from(value: bool) -> Self { + match value { + false => ButtonState::Released, + true => ButtonState::Latched, + } + } +} + +#[derive(Debug, PartialEq, Copy, Clone)] +pub struct InputStringOptions { + pub transparent: bool, + pub auto_wrap: bool, + pub wrap_on_hyphen: bool, +} + +impl From for InputStringOptions { + fn from(value: u8) -> Self { + let mut bit_data = value.view_bits::().to_bitvec(); + InputStringOptions { + transparent: bit_data.pop().unwrap(), + auto_wrap: bit_data.pop().unwrap(), + wrap_on_hyphen: bit_data.pop().unwrap(), + } + } +} + +impl From for u8 { + fn from(value: InputStringOptions) -> u8 { + let mut bit_data: BitVec = BitVec::new(); + bit_data.push(value.transparent); + bit_data.push(value.auto_wrap); + bit_data.push(value.wrap_on_hyphen); + bit_data.extend([0; 5]); + bit_data.load::() + } +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Alignment { + pub horizontal: HorizontalAlignment, + pub vertical: VerticalAlignment, +} + +impl From for Alignment { + fn from(value: u8) -> Self { + let mut bit_data = value.view_bits::().to_bitvec(); + Alignment { + horizontal: HorizontalAlignment::from([ + bit_data.pop().unwrap(), + bit_data.pop().unwrap(), + ]), + vertical: VerticalAlignment::from([bit_data.pop().unwrap(), bit_data.pop().unwrap()]), + } + } +} + +impl From for u8 { + fn from(value: Alignment) -> Self { + let mut bit_data: BitVec = BitVec::new(); + let horizontal_align: [bool; 2] = value.horizontal.into(); + let vertical_align: [bool; 2] = value.vertical.into(); + + bit_data.push(horizontal_align[0]); + bit_data.push(horizontal_align[1]); + + bit_data.push(vertical_align[0]); + bit_data.push(vertical_align[1]); + + bit_data.load::() + } +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum HorizontalAlignment { + Left = 0, + Middle = 1, + Right = 2, + Reserved = 3, +} + +impl From<[bool; 2]> for HorizontalAlignment { + fn from(value: [bool; 2]) -> Self { + match value[0] { + false => match value[1] { + false => HorizontalAlignment::Left, + true => HorizontalAlignment::Middle, + }, + true => match value[1] { + false => HorizontalAlignment::Middle, + true => HorizontalAlignment::Reserved, + }, + } + } +} + +impl From for [bool; 2] { + fn from(value: HorizontalAlignment) -> Self { + match value { + HorizontalAlignment::Left => [false, false], + HorizontalAlignment::Middle => [false, true], + HorizontalAlignment::Right => [true, false], + HorizontalAlignment::Reserved => [true, true], + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum VerticalAlignment { + Top = 0, + Middle = 1, + Bottom = 2, + Reserved = 3, +} + +impl From<[bool; 2]> for VerticalAlignment { + fn from(value: [bool; 2]) -> Self { + match value[0] { + false => match value[1] { + false => VerticalAlignment::Top, + true => VerticalAlignment::Middle, + }, + true => match value[1] { + false => VerticalAlignment::Bottom, + true => VerticalAlignment::Reserved, + }, + } + } +} + +impl From for [bool; 2] { + fn from(value: VerticalAlignment) -> Self { + match value { + VerticalAlignment::Top => [false, false], + VerticalAlignment::Middle => [false, true], + VerticalAlignment::Bottom => [true, false], + VerticalAlignment::Reserved => [true, true], + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct InputNumberOptions { + pub enabled: bool, + pub real_time_editing: bool, +} + +impl From for InputNumberOptions { + fn from(value: u8) -> Self { + let mut bit_data = value.view_bits::().to_bitvec(); + InputNumberOptions { + enabled: bit_data.pop().unwrap(), + real_time_editing: bit_data.pop().unwrap(), + } + } +} + +impl From for u8 { + fn from(value: InputNumberOptions) -> u8 { + let mut bit_data: BitVec = BitVec::new(); + bit_data.push(value.enabled); + bit_data.push(value.real_time_editing); + bit_data.extend([0; 6]); + bit_data.load::() + } +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum FormatType { + Decimal, + Exponential, +} + +impl From for FormatType { + fn from(value: bool) -> Self { + match value { + false => FormatType::Decimal, + true => FormatType::Exponential, + } + } +} + +impl From for bool { + fn from(value: FormatType) -> Self { + match value { + FormatType::Decimal => false, + FormatType::Exponential => true, + } + } +} + +#[derive(Debug, PartialEq, Copy, Clone)] +pub struct InputListOptions { + pub enabled: bool, + pub real_time_editing: bool, +} + +impl From for InputListOptions { + fn from(value: u8) -> Self { + let mut bit_data = value.view_bits::().to_bitvec(); + InputListOptions { + enabled: bit_data.pop().unwrap(), + real_time_editing: bit_data.pop().unwrap(), + } + } +} + +impl From for u8 { + fn from(value: InputListOptions) -> u8 { + let mut bit_data: BitVec = BitVec::new(); + bit_data.push(value.enabled); + bit_data.push(value.real_time_editing); + bit_data.extend([0; 6]); + bit_data.load::() + } +} + +#[derive(Debug, PartialEq, Copy, Clone)] +pub struct OutputStringOptions { + pub transparent: bool, + pub auto_wrap: bool, + pub wrap_on_hyphen: bool, +} + +impl From for OutputStringOptions { + fn from(value: u8) -> Self { + let mut bit_data = value.view_bits::().to_bitvec(); + OutputStringOptions { + transparent: bit_data.pop().unwrap(), + auto_wrap: bit_data.pop().unwrap(), + wrap_on_hyphen: bit_data.pop().unwrap(), + } + } +} + +#[derive(Debug, PartialEq, Clone, Copy)] +pub struct NumberOptions { + pub transparent: bool, + pub display_leading_zeros: bool, + pub display_zero_as_blank: bool, + pub truncate: bool, +} + +impl From for NumberOptions { + fn from(value: u8) -> Self { + let mut bit_data = value.view_bits::().to_bitvec(); + NumberOptions { + transparent: bit_data.pop().unwrap(), + display_leading_zeros: bit_data.pop().unwrap(), + display_zero_as_blank: bit_data.pop().unwrap(), + truncate: bit_data.pop().unwrap(), + } + } +} + +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum LineDirection { + TopLeftToBottomRight, + BottomLeftToTopRight, +} + +impl From for LineDirection { + fn from(value: u8) -> Self { + match value { + 0 => LineDirection::TopLeftToBottomRight, + 1 => LineDirection::BottomLeftToTopRight, + _ => panic!("Invalid line direction"), + } + } +} + +impl From for u8 { + fn from(value: LineDirection) -> Self { + match value { + LineDirection::TopLeftToBottomRight => 0, + LineDirection::BottomLeftToTopRight => 1, + } + } +} + +impl From for u8 { + fn from(value: NumberOptions) -> Self { + let mut bit_data: BitVec = BitVec::new(); + bit_data.push(value.transparent); + bit_data.push(value.display_leading_zeros); + bit_data.push(value.display_zero_as_blank); + bit_data.push(value.truncate); + bit_data.extend([0; 4]); + bit_data.load::() + } +} + +impl From for u8 { + fn from(value: OutputStringOptions) -> u8 { + let mut bit_data: BitVec = BitVec::new(); + bit_data.push(value.transparent); + bit_data.push(value.auto_wrap); + bit_data.push(value.wrap_on_hyphen); + bit_data.extend([0; 5]); + bit_data.load::() + } +} + +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum ColorFormat { + ColorMonochrome, + Color4Bit, + Color8Bit, +} + +impl From for u8 { + fn from(value: ColorFormat) -> Self { + match value { + ColorFormat::ColorMonochrome => 0, + ColorFormat::Color4Bit => 1, + ColorFormat::Color8Bit => 2, + } + } +} + +impl From for ColorFormat { + fn from(value: u8) -> Self { + match value { + 0 => ColorFormat::ColorMonochrome, + 1 => ColorFormat::Color4Bit, + 2 => ColorFormat::Color8Bit, + _ => panic!("Invalid color format: {}", value), + } + } +} + +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum ColorOption { + ForegroundBackground, + LineFontFill, +} + +impl From for ColorOption { + fn from(value: bool) -> Self { + match value { + false => ColorOption::ForegroundBackground, + true => ColorOption::LineFontFill, + } + } +} + +impl From for bool { + fn from(value: ColorOption) -> Self { + match value { + ColorOption::ForegroundBackground => false, + ColorOption::LineFontFill => true, + } + } +} + +#[derive(Debug, PartialEq, Copy, Clone)] +pub struct GraphicsContextOptions { + pub transparent: bool, + pub color: ColorOption, +} + +impl From for GraphicsContextOptions { + fn from(value: u8) -> Self { + let mut bit_data = value.view_bits::().to_bitvec(); + GraphicsContextOptions { + transparent: bit_data.pop().unwrap(), + color: bit_data.pop().unwrap().into(), + } + } +} + +impl From for u8 { + fn from(value: GraphicsContextOptions) -> u8 { + let mut bit_data: BitVec = BitVec::new(); + bit_data.push(value.transparent); + bit_data.push(value.color.into()); + bit_data.extend([0; 6]); + bit_data.load::() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct KeyGroupOptions { + pub available: bool, + pub transparent: bool, +} + +impl From for KeyGroupOptions { + fn from(value: u8) -> Self { + let mut bit_data = value.view_bits::().to_bitvec(); + KeyGroupOptions { + available: bit_data.pop().unwrap(), + transparent: bit_data.pop().unwrap(), + } + } +} + +impl From for u8 { + fn from(value: KeyGroupOptions) -> u8 { + let mut bit_data: BitVec = BitVec::new(); + bit_data.push(value.available); + bit_data.push(value.transparent); + bit_data.extend([0; 6]); + bit_data.load::() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DeflectionDirection { + AntiClockwise, + Clockwise, +} + +impl From for DeflectionDirection { + fn from(value: bool) -> Self { + match value { + false => DeflectionDirection::AntiClockwise, + true => DeflectionDirection::Clockwise, + } + } +} + +impl From for bool { + fn from(value: DeflectionDirection) -> Self { + match value { + DeflectionDirection::AntiClockwise => false, + DeflectionDirection::Clockwise => true, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct OutputMeterOptions { + pub draw_arc: bool, + pub draw_border: bool, + pub draw_ticks: bool, + pub deflection_direction: DeflectionDirection, +} + +impl From for OutputMeterOptions { + fn from(value: u8) -> Self { + let mut bit_data = value.view_bits::().to_bitvec(); + OutputMeterOptions { + draw_arc: bit_data.pop().unwrap(), + draw_border: bit_data.pop().unwrap(), + draw_ticks: bit_data.pop().unwrap(), + deflection_direction: bit_data.pop().unwrap().into(), + } + } +} + +impl From for u8 { + fn from(value: OutputMeterOptions) -> u8 { + let mut bit_data: BitVec = BitVec::new(); + bit_data.push(value.draw_arc); + bit_data.push(value.draw_border); + bit_data.push(value.draw_ticks); + bit_data.push(value.deflection_direction.into()); + bit_data.extend([0; 4]); + bit_data.load::() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum BarGraphType { + Filled, + NotFilled, +} + +impl From for BarGraphType { + fn from(value: bool) -> Self { + match value { + false => BarGraphType::Filled, + true => BarGraphType::NotFilled, + } + } +} + +impl From for bool { + fn from(value: BarGraphType) -> Self { + match value { + BarGraphType::Filled => false, + BarGraphType::NotFilled => true, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum AxisOrientation { + Vertical, + Horizontal, +} + +impl From for AxisOrientation { + fn from(value: bool) -> Self { + match value { + false => AxisOrientation::Vertical, + true => AxisOrientation::Horizontal, + } + } +} + +impl From for bool { + fn from(value: AxisOrientation) -> Self { + match value { + AxisOrientation::Vertical => false, + AxisOrientation::Horizontal => true, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum GrowDirection { + GrowLeftDown, + GrowRightUp, +} + +impl From for GrowDirection { + fn from(value: bool) -> Self { + match value { + false => GrowDirection::GrowLeftDown, + true => GrowDirection::GrowRightUp, + } + } +} + +impl From for bool { + fn from(value: GrowDirection) -> Self { + match value { + GrowDirection::GrowLeftDown => false, + GrowDirection::GrowRightUp => true, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct OutputLinearBarGraphOptions { + pub draw_border: bool, + pub draw_target_line: bool, + pub draw_ticks: bool, + pub bar_graph_type: BarGraphType, + pub axis_orientation: AxisOrientation, + pub grow_direction: GrowDirection, +} + +impl From for OutputLinearBarGraphOptions { + fn from(value: u8) -> Self { + let mut bit_data = value.view_bits::().to_bitvec(); + OutputLinearBarGraphOptions { + draw_border: bit_data.pop().unwrap(), + draw_target_line: bit_data.pop().unwrap(), + draw_ticks: bit_data.pop().unwrap(), + bar_graph_type: bit_data.pop().unwrap().into(), + axis_orientation: bit_data.pop().unwrap().into(), + grow_direction: bit_data.pop().unwrap().into(), + } + } +} + +impl From for u8 { + fn from(value: OutputLinearBarGraphOptions) -> u8 { + let mut bit_data: BitVec = BitVec::new(); + bit_data.push(value.draw_border); + bit_data.push(value.draw_target_line); + bit_data.push(value.draw_ticks); + bit_data.push(value.bar_graph_type.into()); + bit_data.push(value.axis_orientation.into()); + bit_data.push(value.grow_direction.into()); + bit_data.extend([0; 2]); + bit_data.load::() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct OutputArchedBarGraphOptions { + pub draw_border: bool, + pub draw_target_line: bool, + pub bar_graph_type: BarGraphType, + pub axis_orientation: AxisOrientation, + pub grow_direction: GrowDirection, + pub deflection_direction: DeflectionDirection, +} + +impl From for OutputArchedBarGraphOptions { + fn from(value: u8) -> Self { + let mut bit_data = value.view_bits::().to_bitvec(); + let draw_border = bit_data.pop().unwrap(); + let draw_target_line = bit_data.pop().unwrap(); + bit_data.pop(); //undefined bit + + OutputArchedBarGraphOptions { + draw_border, + draw_target_line, + bar_graph_type: bit_data.pop().unwrap().into(), + axis_orientation: bit_data.pop().unwrap().into(), + grow_direction: bit_data.pop().unwrap().into(), + deflection_direction: bit_data.pop().unwrap().into(), + } + } +} + +impl From for u8 { + fn from(value: OutputArchedBarGraphOptions) -> u8 { + let mut bit_data: BitVec = BitVec::new(); + bit_data.push(value.draw_border); + bit_data.push(value.draw_target_line); + bit_data.push(false); //undefined bit + bit_data.push(value.bar_graph_type.into()); + bit_data.push(value.axis_orientation.into()); + bit_data.push(value.grow_direction.into()); + bit_data.push(value.deflection_direction.into()); + bit_data.extend([0; 1]); + bit_data.load::() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DataCodeType { + Raw, + RunLength, +} + +impl From for DataCodeType { + fn from(value: bool) -> Self { + match value { + false => DataCodeType::Raw, + true => DataCodeType::RunLength, + } + } +} + +impl From for bool { + fn from(value: DataCodeType) -> Self { + match value { + DataCodeType::Raw => false, + DataCodeType::RunLength => true, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct PictureGraphicOptions { + pub transparent: bool, + pub flashing: bool, + pub data_code_type: DataCodeType, +} + +impl From for PictureGraphicOptions { + fn from(value: u8) -> Self { + let mut bit_data = value.view_bits::().to_bitvec(); + PictureGraphicOptions { + transparent: bit_data.pop().unwrap(), + flashing: bit_data.pop().unwrap(), + data_code_type: bit_data.pop().unwrap().into(), + } + } +} + +impl From for u8 { + fn from(value: PictureGraphicOptions) -> u8 { + let mut bit_data: BitVec = BitVec::new(); + bit_data.push(value.transparent); + bit_data.push(value.flashing); + bit_data.push(value.data_code_type.into()); + bit_data.extend([0; 5]); + bit_data.load::() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ExternalObjectDefinitionOptions { + pub enabled: bool, +} + +impl From for ExternalObjectDefinitionOptions { + fn from(value: u8) -> Self { + let mut bit_data = value.view_bits::().to_bitvec(); + ExternalObjectDefinitionOptions { + enabled: bit_data.pop().unwrap(), + } + } +} + +impl From for u8 { + fn from(value: ExternalObjectDefinitionOptions) -> u8 { + let mut bit_data: BitVec = BitVec::new(); + bit_data.push(value.enabled); + bit_data.extend([0; 7]); + bit_data.load::() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ExternalReferenceNameOptions { + pub enabled: bool, +} + +impl From for ExternalReferenceNameOptions { + fn from(value: u8) -> Self { + let mut bit_data = value.view_bits::().to_bitvec(); + ExternalReferenceNameOptions { + enabled: bit_data.pop().unwrap(), + } + } +} + +impl From for u8 { + fn from(value: ExternalReferenceNameOptions) -> u8 { + let mut bit_data: BitVec = BitVec::new(); + bit_data.push(value.enabled); + bit_data.extend([0; 7]); + bit_data.load::() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum AnimationSequence { + SingleShot, + Loop, +} + +impl From for AnimationSequence { + fn from(value: bool) -> Self { + match value { + false => AnimationSequence::SingleShot, + true => AnimationSequence::Loop, + } + } +} + +impl From for bool { + fn from(value: AnimationSequence) -> Self { + match value { + AnimationSequence::SingleShot => false, + AnimationSequence::Loop => true, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DisabledBehaviour { + Pause, + ResetToFirst, + DefaultObject, + Blank, +} + +impl From<[bool; 2]> for DisabledBehaviour { + fn from(value: [bool; 2]) -> Self { + match value { + [false, false] => DisabledBehaviour::Pause, + [false, true] => DisabledBehaviour::ResetToFirst, + [true, false] => DisabledBehaviour::DefaultObject, + [true, true] => DisabledBehaviour::Blank, + } + } +} + +impl From for [bool; 2] { + fn from(value: DisabledBehaviour) -> Self { + match value { + DisabledBehaviour::Pause => [false, false], + DisabledBehaviour::ResetToFirst => [false, true], + DisabledBehaviour::DefaultObject => [true, false], + DisabledBehaviour::Blank => [true, true], + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AnimationOptions { + pub animation_sequence: AnimationSequence, + pub disabled_behaviour: DisabledBehaviour, +} + +impl From for AnimationOptions { + fn from(value: u8) -> Self { + let mut bit_data = value.view_bits::().to_bitvec(); + AnimationOptions { + animation_sequence: bit_data.pop().unwrap().into(), + disabled_behaviour: DisabledBehaviour::from([ + bit_data.pop().unwrap(), + bit_data.pop().unwrap(), + ]), + } + } +} + +impl From for u8 { + fn from(value: AnimationOptions) -> u8 { + let mut bit_data: BitVec = BitVec::new(); + bit_data.push(value.animation_sequence.into()); + let disabled_behaviour: [bool; 2] = value.disabled_behaviour.into(); + bit_data.push(disabled_behaviour[0]); + bit_data.push(disabled_behaviour[1]); + bit_data.extend([0; 5]); + bit_data.load::() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ColourPaletteOptions {} + +impl From for ColourPaletteOptions { + fn from(value: u8) -> Self { + let mut _bit_data = value.view_bits::().to_bitvec(); + ColourPaletteOptions {} + } +} + +impl From for u8 { + fn from(_value: ColourPaletteOptions) -> u8 { + let mut bit_data: BitVec = BitVec::new(); + bit_data.extend([0; 8]); + bit_data.load::() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ScaledGraphicOptions { + pub flashing: bool, +} + +impl From for ScaledGraphicOptions { + fn from(value: u8) -> Self { + let mut bit_data = value.view_bits::().to_bitvec(); + ScaledGraphicOptions { + flashing: bit_data.pop().unwrap(), + } + } +} + +impl From for u8 { + fn from(value: ScaledGraphicOptions) -> u8 { + let mut bit_data: BitVec = BitVec::new(); + bit_data.push(value.flashing); + bit_data.extend([0; 7]); + bit_data.load::() + } +} diff --git a/src/object_pool/object_id.rs b/src/object_pool/object_id.rs new file mode 100644 index 0000000..747649e --- /dev/null +++ b/src/object_pool/object_id.rs @@ -0,0 +1,115 @@ +use crate::object_pool::ParseError; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ObjectId { + id: u16, +} + +impl ObjectId { + const NULL: ObjectId = ObjectId { id: u16::MAX }; + + pub fn new(id: u16) -> Result { + if id == Self::NULL.id { + Err(ParseError::UnknownObjectType) + } else { + Ok(ObjectId { id }) + } + } +} + +pub struct NullableObjectId(Option); + +impl NullableObjectId { + pub const NULL: NullableObjectId = NullableObjectId(None); + pub fn new(id: u16) -> Self { + if id == ObjectId::NULL.id { + NullableObjectId(None) + } else { + NullableObjectId(Some(ObjectId::new(id).unwrap())) + } + } +} + +impl Default for NullableObjectId { + fn default() -> Self { + NullableObjectId::NULL + } +} + +impl From for NullableObjectId { + fn from(id: u16) -> Self { + NullableObjectId::new(id) + } +} + +impl From for u16 { + fn from(id: NullableObjectId) -> Self { + match id.0 { + Some(id) => id.id, + None => u16::from(ObjectId::NULL), + } + } +} + +impl From for NullableObjectId { + fn from(id: ObjectId) -> Self { + if id == ObjectId::NULL { + NullableObjectId(None) + } else { + NullableObjectId(Some(id)) + } + } +} + +impl Default for ObjectId { + fn default() -> Self { + Self::new(0).unwrap() + } +} +impl TryFrom for ObjectId { + type Error = ParseError; + + fn try_from(id: u16) -> Result { + ObjectId::new(id) + } +} + +impl From for u16 { + fn from(val: ObjectId) -> Self { + val.id + } +} +impl TryFrom<[u8; 2]> for ObjectId { + type Error = ParseError; + + fn try_from(val: [u8; 2]) -> Result { + ObjectId::new(u16::from_le_bytes(val)) + } +} +impl From for [u8; 2] { + fn from(val: ObjectId) -> Self { + val.id.to_le_bytes() + } +} +// impl From> for ObjectId { +// fn from(val: Vec) -> Self { +// let val: ObjectId = val.as_slice().into(); +// val +// } +// } +// impl From for Vec { +// fn from(val: ObjectId) -> Self { +// let val: [u8;2] = val.into(); +// val.to_vec() +// } +// } +impl TryFrom<&[u8]> for ObjectId { + type Error = ParseError; + + fn try_from(val: &[u8]) -> Result { + match val.len() { + 2.. => Ok(ObjectId::new(u16::from_le_bytes([val[0], val[1]]))?), + _ => Err(ParseError::DataEmpty), + } + } +} diff --git a/src/object_pool/object_pool.rs b/src/object_pool/object_pool.rs new file mode 100644 index 0000000..1f6bee7 --- /dev/null +++ b/src/object_pool/object_pool.rs @@ -0,0 +1,327 @@ +use crate::object_pool::colour::Colour; +use crate::object_pool::object::{ + AlarmMask, Button, Container, DataMask, GraphicsContext, InputBoolean, InputList, InputNumber, + InputString, Key, KeyGroup, LineAttributes, Object, OutputLine, OutputList, OutputNumber, + OutputString, PictureGraphic, SoftKeyMask, WindowMask, WorkingSet, +}; +use crate::object_pool::object_id::ObjectId; +use crate::object_pool::vt_version::VtVersion; +use crate::object_pool::ObjectType; +use core::cell::Cell; + +#[derive(Debug)] +pub struct ObjectPool { + objects: Vec, + colour_map: [u8; 256], + colour_palette: [Colour; 256], + _supported_vt_version: VtVersion, + + size_cache: Cell>, +} + +impl ObjectPool { + pub fn new() -> Self { + // Setup the default colour map + let mut colour_map = [0xFFu8; 256]; + for i in 0..(colour_map.len() as u8) { + colour_map[i as usize] = i; + } + + ObjectPool { + objects: Vec::new(), + colour_map, + colour_palette: Colour::COLOUR_PALETTE, + _supported_vt_version: VtVersion::default(), + + size_cache: Cell::new(None), + } + } + + pub fn size(&self) -> usize { + if self.size_cache.get().is_none() { + self.size_cache.set(Some(self.as_iop().len())); + } + self.size_cache.get().unwrap_or_default() + } + + /// + /// Loads the binary encoded object pool from a buffer in accordance + /// with ISO 11783-6 Annex B (object definitions) and returns the + /// parsed [`ObjectPool`]. + /// + /// # Arguments + /// + /// * `data` - A buffer containing the binary encoded object pool + /// + /// # Examples + /// ``` + /// use std::fs::File; + /// use std::io::Read; + /// use std::path::Path; + /// use ag_iso_stack::object_pool::ObjectPool; + /// + /// let example_path = Path::new("C:/project/resources/test/AgIsoStack-rs-test-pool.iop"); + /// let mut pool_file = match File::open(example_path) { + /// Err(why) => panic!("couldn't open {:?}: {}", example_path.to_str(), why), + /// Ok(file) => file, + /// }; + /// + /// let mut buffer = Vec::new(); + /// match pool_file.read_to_end(&mut buffer) { + /// Ok(size) => size, + /// Err(why) => panic!("Could not read object pool file: {why}"), + /// }; + /// + /// let object_pool = ObjectPool::from_iop(buffer); + /// ``` + /// + pub fn from_iop(data: I) -> Self + where + I: IntoIterator, + { + let mut data = data.into_iter(); + + let mut op = Self::new(); + + while let Ok(o) = Object::read(&mut data) { + op.objects.push(o); + } + + op + } + + pub fn as_iop(&self) -> Vec { + let mut data = Vec::new(); + + for obj in &self.objects { + data.extend(obj.write()); + } + + data + } + + pub fn add(&mut self, obj: Object) { + self.objects.push(obj); + } + + pub fn object_by_id(&self, id: ObjectId) -> Option<&Object> { + self.objects.iter().find(|&o| o.id() == id) + } + + pub fn objects_by_type(&self, object_type: ObjectType) -> Vec<&Object> { + self.objects + .iter() + .filter(|&o| o.object_type() == object_type) + .collect() + } + + // Get objects by type + + pub fn working_set_object(&self) -> Option<&WorkingSet> { + match &self.objects_by_type(ObjectType::WorkingSet).first() { + Some(Object::WorkingSet(o)) => Some(o), + _ => None, + } + } + + pub fn data_mask_objects(&self) -> Vec<&DataMask> { + let r: Vec<&DataMask> = self + .objects_by_type(ObjectType::DataMask) + .iter() + .filter_map(|&o| match o { + Object::DataMask(o) => Some(o), + _ => None, + }) + .collect(); + r + } + + pub fn picture_graphic_objects(&self) -> Vec<&PictureGraphic> { + let r: Vec<&PictureGraphic> = self + .objects_by_type(ObjectType::PictureGraphic) + .iter() + .filter_map(|&o| match o { + Object::PictureGraphic(o) => Some(o), + _ => None, + }) + .collect(); + r + } + + // Get typed objects by id + + pub fn data_mask_object_by_id(&self, id: ObjectId) -> Option<&DataMask> { + match &self.object_by_id(id) { + Some(Object::DataMask(o)) => Some(o), + _ => None, + } + } + + pub fn alarm_mask_object_by_id(&self, id: ObjectId) -> Option<&AlarmMask> { + match &self.object_by_id(id) { + Some(Object::AlarmMask(o)) => Some(o), + _ => None, + } + } + + pub fn soft_key_mask_object_by_id(&self, id: ObjectId) -> Option<&SoftKeyMask> { + match &self.object_by_id(id) { + Some(Object::SoftKeyMask(o)) => Some(o), + _ => None, + } + } + + pub fn key_group_object_by_id(&self, id: ObjectId) -> Option<&KeyGroup> { + match &self.object_by_id(id) { + Some(Object::KeyGroup(o)) => Some(o), + _ => None, + } + } + + pub fn window_mask_object_by_id(&self, id: ObjectId) -> Option<&WindowMask> { + match &self.object_by_id(id) { + Some(Object::WindowMask(o)) => Some(o), + _ => None, + } + } + + pub fn container_object_by_id(&self, id: ObjectId) -> Option<&Container> { + match &self.object_by_id(id) { + Some(Object::Container(o)) => Some(o), + _ => None, + } + } + + pub fn key_object_by_id(&self, id: ObjectId) -> Option<&Key> { + match &self.object_by_id(id) { + Some(Object::Key(o)) => Some(o), + _ => None, + } + } + + pub fn button_object_by_id(&self, id: ObjectId) -> Option<&Button> { + match &self.object_by_id(id) { + Some(Object::Button(o)) => Some(o), + _ => None, + } + } + + pub fn input_boolean_object_by_id(&self, id: ObjectId) -> Option<&InputBoolean> { + match &self.object_by_id(id) { + Some(Object::InputBoolean(o)) => Some(o), + _ => None, + } + } + + pub fn input_string_object_by_id(&self, id: ObjectId) -> Option<&InputString> { + match &self.object_by_id(id) { + Some(Object::InputString(o)) => Some(o), + _ => None, + } + } + + pub fn input_number_object_by_id(&self, id: ObjectId) -> Option<&InputNumber> { + match &self.object_by_id(id) { + Some(Object::InputNumber(o)) => Some(o), + _ => None, + } + } + + pub fn input_list_object_by_id(&self, id: ObjectId) -> Option<&InputList> { + match &self.object_by_id(id) { + Some(Object::InputList(o)) => Some(o), + _ => None, + } + } + + pub fn output_string_object_by_id(&self, id: ObjectId) -> Option<&OutputString> { + match &self.object_by_id(id) { + Some(Object::OutputString(o)) => Some(o), + _ => None, + } + } + + pub fn output_number_object_by_id(&self, id: ObjectId) -> Option<&OutputNumber> { + match &self.object_by_id(id) { + Some(Object::OutputNumber(o)) => Some(o), + _ => None, + } + } + + pub fn output_list_object_by_id(&self, id: ObjectId) -> Option<&OutputList> { + match &self.object_by_id(id) { + Some(Object::OutputList(o)) => Some(o), + _ => None, + } + } + + pub fn output_line_object_by_id(&self, id: ObjectId) -> Option<&OutputLine> { + match &self.object_by_id(id) { + Some(Object::OutputLine(o)) => Some(o), + _ => None, + } + } + + pub fn line_attributes_object_by_id(&self, id: ObjectId) -> Option<&LineAttributes> { + match &self.object_by_id(id) { + Some(Object::LineAttributes(o)) => Some(o), + _ => None, + } + } + + pub fn graphics_context_object_by_id(&self, id: ObjectId) -> Option<&GraphicsContext> { + match &self.object_by_id(id) { + Some(Object::GraphicsContext(o)) => Some(o), + _ => None, + } + } + + pub fn color_by_index(&self, index: u8) -> Colour { + self.colour_palette[self.colour_map[index as usize] as usize] + } +} + +impl Default for ObjectPool { + fn default() -> Self { + Self::new() + } +} + +/* !todo: implement tests / fix tests +#[cfg(test)] +mod tests { + use super::*; + use std::fs::File; + use std::io::Read; + use std::path::Path; + + fn get_pool_path() -> Box { + Box::from(Path::new(&format!( + "{}/resources/test/AgIsoStack-rs-test-pool.iop", + match std::env::var("CARGO_MANIFEST_DIR") { + Err(_why) => + panic!("could not find environment variable 'CARGO_MANIFEST_DIR': {_why}!"), + Ok(path) => path, + } + ))) + } + + fn get_pool_file() -> File { + match File::open(get_pool_path()) { + Err(why) => panic!("couldn't open {:?}: {}", get_pool_path().to_str(), why), + Ok(file) => file, + } + } + + #[test] + fn test_from_iop() { + let mut buffer = Vec::new(); + match get_pool_file().read_to_end(&mut buffer) { + Ok(size) => size, + Err(why) => panic!("Could not read object pool file: {why}"), + }; + + let _object_pool = ObjectPool::from_iop(buffer); + } +} +*/ diff --git a/src/object_pool/object_type.rs b/src/object_pool/object_type.rs new file mode 100644 index 0000000..950384e --- /dev/null +++ b/src/object_pool/object_type.rs @@ -0,0 +1,170 @@ +use crate::object_pool::ParseError; +use crate::object_pool::ParseError::UnknownObjectType; + +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum ObjectType { + WorkingSet = 0, + DataMask = 1, + AlarmMask = 2, + Container = 3, + SoftKeyMask = 4, + Key = 5, + Button = 6, + InputBoolean = 7, + InputString = 8, + InputNumber = 9, + InputList = 10, + OutputString = 11, + OutputNumber = 12, + OutputLine = 13, + OutputRectangle = 14, + OutputEllipse = 15, + OutputPolygon = 16, + OutputMeter = 17, + OutputLinearBarGraph = 18, + OutputArchedBarGraph = 19, + PictureGraphic = 20, + NumberVariable = 21, + StringVariable = 22, + FontAttributes = 23, + LineAttributes = 24, + FillAttributes = 25, + InputAttributes = 26, + ObjectPointer = 27, + Macro = 28, + AuxiliaryFunctionType1 = 29, + AuxiliaryInputType1 = 30, + AuxiliaryFunctionType2 = 31, + AuxiliaryInputType2 = 32, + AuxiliaryControlDesignatorType2 = 33, + WindowMask = 34, + KeyGroup = 35, + GraphicsContext = 36, + OutputList = 37, + ExtendedInputAttributes = 38, + ColourMap = 39, + ObjectLabelReferenceList = 40, + ExternalObjectDefinition = 41, + ExternalReferenceName = 42, + ExternalObjectPointer = 43, + Animation = 44, + ColourPalette = 45, + GraphicData = 46, + WorkingSetSpecialControls = 47, + ScaledGraphic = 48, +} + +impl TryFrom for ObjectType { + type Error = ParseError; + + fn try_from(val: u8) -> Result { + match val { + 0 => Ok(Self::WorkingSet), + 1 => Ok(Self::DataMask), + 2 => Ok(Self::AlarmMask), + 3 => Ok(Self::Container), + 4 => Ok(Self::SoftKeyMask), + 5 => Ok(Self::Key), + 6 => Ok(Self::Button), + 7 => Ok(Self::InputBoolean), + 8 => Ok(Self::InputString), + 9 => Ok(Self::InputNumber), + 10 => Ok(Self::InputList), + 11 => Ok(Self::OutputString), + 12 => Ok(Self::OutputNumber), + 13 => Ok(Self::OutputLine), + 14 => Ok(Self::OutputRectangle), + 15 => Ok(Self::OutputEllipse), + 16 => Ok(Self::OutputPolygon), + 17 => Ok(Self::OutputMeter), + 18 => Ok(Self::OutputLinearBarGraph), + 19 => Ok(Self::OutputArchedBarGraph), + 20 => Ok(Self::PictureGraphic), + 21 => Ok(Self::NumberVariable), + 22 => Ok(Self::StringVariable), + 23 => Ok(Self::FontAttributes), + 24 => Ok(Self::LineAttributes), + 25 => Ok(Self::FillAttributes), + 26 => Ok(Self::InputAttributes), + 27 => Ok(Self::ObjectPointer), + 28 => Ok(Self::Macro), + 29 => Ok(Self::AuxiliaryFunctionType1), + 30 => Ok(Self::AuxiliaryInputType1), + 31 => Ok(Self::AuxiliaryFunctionType2), + 32 => Ok(Self::AuxiliaryInputType2), + 33 => Ok(Self::AuxiliaryControlDesignatorType2), + 34 => Ok(Self::WindowMask), + 35 => Ok(Self::KeyGroup), + 36 => Ok(Self::GraphicsContext), + 37 => Ok(Self::OutputList), + 38 => Ok(Self::ExtendedInputAttributes), + 39 => Ok(Self::ColourMap), + 40 => Ok(Self::ObjectLabelReferenceList), + 41 => Ok(Self::ExternalObjectDefinition), + 42 => Ok(Self::ExternalReferenceName), + 43 => Ok(Self::ExternalObjectPointer), + 44 => Ok(Self::Animation), + 45 => Ok(Self::ColourPalette), + 46 => Ok(Self::GraphicData), + 47 => Ok(Self::WorkingSetSpecialControls), + 48 => Ok(Self::ScaledGraphic), + _ => Err(UnknownObjectType), + } + } +} + +impl From for u8 { + fn from(val: ObjectType) -> Self { + match val { + ObjectType::WorkingSet => 0, + ObjectType::DataMask => 1, + ObjectType::AlarmMask => 2, + ObjectType::Container => 3, + ObjectType::SoftKeyMask => 4, + ObjectType::Key => 5, + ObjectType::Button => 6, + ObjectType::InputBoolean => 7, + ObjectType::InputString => 8, + ObjectType::InputNumber => 9, + ObjectType::InputList => 10, + ObjectType::OutputString => 11, + ObjectType::OutputNumber => 12, + ObjectType::OutputLine => 13, + ObjectType::OutputRectangle => 14, + ObjectType::OutputEllipse => 15, + ObjectType::OutputPolygon => 16, + ObjectType::OutputMeter => 17, + ObjectType::OutputLinearBarGraph => 18, + ObjectType::OutputArchedBarGraph => 19, + ObjectType::PictureGraphic => 20, + ObjectType::NumberVariable => 21, + ObjectType::StringVariable => 22, + ObjectType::FontAttributes => 23, + ObjectType::LineAttributes => 24, + ObjectType::FillAttributes => 25, + ObjectType::InputAttributes => 26, + ObjectType::ObjectPointer => 27, + ObjectType::Macro => 28, + ObjectType::AuxiliaryFunctionType1 => 29, + ObjectType::AuxiliaryInputType1 => 30, + ObjectType::AuxiliaryFunctionType2 => 31, + ObjectType::AuxiliaryInputType2 => 32, + ObjectType::AuxiliaryControlDesignatorType2 => 33, + ObjectType::WindowMask => 34, + ObjectType::KeyGroup => 35, + ObjectType::GraphicsContext => 36, + ObjectType::OutputList => 37, + ObjectType::ExtendedInputAttributes => 38, + ObjectType::ColourMap => 39, + ObjectType::ObjectLabelReferenceList => 40, + ObjectType::ExternalObjectDefinition => 41, + ObjectType::ExternalReferenceName => 42, + ObjectType::ExternalObjectPointer => 43, + ObjectType::Animation => 44, + ObjectType::ColourPalette => 45, + ObjectType::GraphicData => 46, + ObjectType::WorkingSetSpecialControls => 47, + ObjectType::ScaledGraphic => 48, + } + } +} diff --git a/src/object_pool/reader.rs b/src/object_pool/reader.rs new file mode 100644 index 0000000..ec56f50 --- /dev/null +++ b/src/object_pool/reader.rs @@ -0,0 +1,1384 @@ +use super::*; +use crate::object_pool::colour::Colour; +use crate::object_pool::object::*; +use crate::object_pool::object_attributes::{MacroRef, ObjectLabel, ObjectRef, Point}; +use crate::object_pool::object_id::ObjectId; + +impl Object { + pub fn read(data: &mut dyn Iterator) -> Result { + let id = Self::read_u16(data)?.try_into()?; + let object_type = Self::read_u8(data)?.try_into()?; + + match object_type { + ObjectType::WorkingSet => Self::read_working_set(id, data), + ObjectType::DataMask => Self::read_data_mask(id, data), + ObjectType::AlarmMask => Self::read_alarm_mask(id, data), + ObjectType::Container => Self::read_container(id, data), + ObjectType::SoftKeyMask => Self::read_soft_key_mask(id, data), + ObjectType::Key => Self::read_key(id, data), + ObjectType::Button => Self::read_button(id, data), + ObjectType::InputBoolean => Self::read_input_boolean(id, data), + ObjectType::InputString => Self::read_input_string(id, data), + ObjectType::InputNumber => Self::read_input_number(id, data), + ObjectType::InputList => Self::read_input_list(id, data), + ObjectType::OutputString => Self::read_output_string(id, data), + ObjectType::OutputNumber => Self::read_output_number(id, data), + ObjectType::OutputLine => Self::read_output_line(id, data), + ObjectType::OutputRectangle => Self::read_output_rectangle(id, data), + ObjectType::OutputEllipse => Self::read_output_ellipse(id, data), + ObjectType::OutputPolygon => Self::read_output_polygon(id, data), + ObjectType::OutputMeter => Self::read_output_meter(id, data), + ObjectType::OutputLinearBarGraph => Self::read_output_linear_bar_graph(id, data), + ObjectType::OutputArchedBarGraph => Self::read_output_arched_bar_graph(id, data), + ObjectType::PictureGraphic => Self::read_picture_graphic(id, data), + ObjectType::NumberVariable => Self::read_number_variable(id, data), + ObjectType::StringVariable => Self::read_string_variable(id, data), + ObjectType::FontAttributes => Self::read_font_attributes(id, data), + ObjectType::LineAttributes => Self::read_line_attributes(id, data), + ObjectType::FillAttributes => Self::read_fill_attributes(id, data), + ObjectType::InputAttributes => Self::read_input_attributes(id, data), + ObjectType::ObjectPointer => Self::read_object_pointer(id, data), + ObjectType::Macro => Self::read_macro(id, data), + ObjectType::AuxiliaryFunctionType1 => Self::read_auxiliary_function_type1(id, data), + ObjectType::AuxiliaryInputType1 => Self::read_auxiliary_input_type1(id, data), + ObjectType::AuxiliaryFunctionType2 => Self::read_auxiliary_function_type2(id, data), + ObjectType::AuxiliaryInputType2 => Self::read_auxiliary_input_type2(id, data), + ObjectType::AuxiliaryControlDesignatorType2 => { + Self::read_auxiliary_control_designator_type2(id, data) + } + ObjectType::WindowMask => Self::read_window_mask(id, data), + ObjectType::KeyGroup => Self::read_key_group(id, data), + ObjectType::GraphicsContext => Self::read_graphics_context(id, data), + ObjectType::OutputList => Self::read_output_list(id, data), + ObjectType::ExtendedInputAttributes => Self::read_extended_input_attributes(id, data), + ObjectType::ColourMap => Self::read_colour_map(id, data), + ObjectType::ObjectLabelReferenceList => { + Self::read_object_label_reference_list(id, data) + } + ObjectType::ExternalObjectDefinition => Self::read_external_object_definition(id, data), + ObjectType::ExternalReferenceName => Self::read_external_reference_name(id, data), + ObjectType::ExternalObjectPointer => Self::read_external_object_pointer(id, data), + ObjectType::Animation => Self::read_animation(id, data), + ObjectType::ColourPalette => Self::read_colour_palette(id, data), + ObjectType::GraphicData => Self::read_graphic_data(id, data), + ObjectType::WorkingSetSpecialControls => { + Self::read_working_set_special_controls(id, data) + } + ObjectType::ScaledGraphic => Self::read_scaled_graphic(id, data), + } + } + + /* READ COMMON TYPES */ + + fn read_objects( + data: &mut dyn Iterator, + nr_of_objects: usize, + ) -> Result, ParseError> { + let mut objs = Vec::new(); + for _ in 0..nr_of_objects { + objs.push(Self::read_u16(data)?.try_into()?); + } + Ok(objs) + } + + fn read_object_refs( + data: &mut dyn Iterator, + nr_of_objects: usize, + ) -> Result, ParseError> { + let mut refs = Vec::new(); + for _ in 0..nr_of_objects { + refs.push(ObjectRef { + id: Self::read_u16(data)?.try_into()?, + offset: Point { + x: Self::read_i16(data)?, + y: Self::read_i16(data)?, + }, + }) + } + Ok(refs) + } + fn read_macro_refs( + data: &mut dyn Iterator, + nr_of_macros: usize, + ) -> Result, ParseError> { + let mut refs = Vec::new(); + for _ in 0..nr_of_macros { + refs.push(MacroRef { + event_id: Self::read_u8(data)?, + macro_id: Self::read_u8(data)?, + }) + } + Ok(refs) + } + fn read_bytes( + data: &mut dyn Iterator, + nr_of_bytes: usize, + ) -> Result, ParseError> { + let mut objs = Vec::new(); + for _ in 0..nr_of_bytes { + objs.push(Self::read_u8(data)?) + } + Ok(objs) + } + fn read_points( + data: &mut dyn Iterator, + nr_of_points: usize, + ) -> Result>, ParseError> { + let mut objs = Vec::new(); + for _ in 0..nr_of_points { + objs.push(Point { + x: Self::read_u16(data)?, + y: Self::read_u16(data)?, + }) + } + Ok(objs) + } + fn read_colours( + data: &mut dyn Iterator, + nr_of_colours: usize, + ) -> Result, ParseError> { + let mut objs = Vec::new(); + for _ in 0..nr_of_colours { + let b = Self::read_u8(data)?; + let g = Self::read_u8(data)?; + let r = Self::read_u8(data)?; + let a = Self::read_u8(data)?; + + objs.push(Colour::new_by_rgba(r, g, b, a)) + } + Ok(objs) + } + fn read_object_labels( + data: &mut dyn Iterator, + nr_of_objects: usize, + ) -> Result, ParseError> { + let mut objs = Vec::new(); + for _ in 0..nr_of_objects { + objs.push(ObjectLabel { + id: Self::read_u16(data)?.try_into()?, + string_variable_reference: Self::read_u16(data)?.try_into()?, + font_type: Self::read_u8(data)?, + graphic_representation: Self::read_u16(data)?.try_into()?, + }) + } + Ok(objs) + } + fn read_language_pairs( + data: &mut dyn Iterator, + nr_of_objects: usize, + ) -> Result, ParseError> { + let mut objs = Vec::new(); + for _ in 0..nr_of_objects { + objs.push((Self::read_string(2, data)?, Self::read_string(2, data)?)) + } + Ok(objs) + } + + fn read_character_ranges( + data: &mut dyn Iterator, + ) -> Result, ParseError> { + let nr_of_character_ranges = Self::read_u8(data)? as usize; + let mut character_ranges = Vec::new(); + + for _ in 0..nr_of_character_ranges { + let character_range = CharacterRange { + first_character: Self::read_u16(data)?, + last_character: Self::read_u16(data)?, + }; + character_ranges.push(character_range); + } + + Ok(character_ranges) + } + + fn read_code_planes(data: &mut dyn Iterator) -> Result, ParseError> { + let mut code_planes = Vec::new(); + let nr_of_code_planes = Self::read_u8(data)? as usize; + + for _ in 0..nr_of_code_planes { + let number = Self::read_u8(data)?; + let character_ranges = Self::read_character_ranges(data)?; + let code_plane = CodePlane { + number, + character_ranges, + }; + + code_planes.push(code_plane); + } + + Ok(code_planes) + } + + fn read_bool(data: &mut dyn Iterator) -> Result { + match data.next() { + Some(d) => { + if d == 0 || d == 1 { + Ok(d == 1) + } else { + Err(ParseError::UnknownObjectType) + } + } + None => Err(ParseError::DataEmpty), + } + } + fn read_u8(data: &mut dyn Iterator) -> Result { + match data.next() { + Some(d) => Ok(d), + None => Err(ParseError::DataEmpty), + } + } + fn read_u16(data: &mut dyn Iterator) -> Result { + let a: Option = data.next(); + let b: Option = data.next(); + + if a.is_none() || b.is_none() { + return Err(ParseError::DataEmpty); + } + + Ok(u16::from_le_bytes([a.unwrap(), b.unwrap()])) + } + fn read_i16(data: &mut dyn Iterator) -> Result { + let a: Option = data.next(); + let b: Option = data.next(); + + if a.is_none() || b.is_none() { + return Err(ParseError::DataEmpty); + } + + Ok(i16::from_le_bytes([a.unwrap(), b.unwrap()])) + } + fn read_u32(data: &mut dyn Iterator) -> Result { + let a: Option = data.next(); + let b: Option = data.next(); + let c: Option = data.next(); + let d: Option = data.next(); + + if a.is_none() || b.is_none() || c.is_none() || d.is_none() { + return Err(ParseError::DataEmpty); + } + + Ok(u32::from_le_bytes([ + a.unwrap(), + b.unwrap(), + c.unwrap(), + d.unwrap(), + ])) + } + fn read_i32(data: &mut dyn Iterator) -> Result { + let a: Option = data.next(); + let b: Option = data.next(); + let c: Option = data.next(); + let d: Option = data.next(); + + if a.is_none() || b.is_none() || c.is_none() || d.is_none() { + return Err(ParseError::DataEmpty); + } + + Ok(i32::from_le_bytes([ + a.unwrap(), + b.unwrap(), + c.unwrap(), + d.unwrap(), + ])) + } + fn read_f32(data: &mut dyn Iterator) -> Result { + let a: Option = data.next(); + let b: Option = data.next(); + let c: Option = data.next(); + let d: Option = data.next(); + + if a.is_none() || b.is_none() || c.is_none() || d.is_none() { + return Err(ParseError::DataEmpty); + } + + Ok(f32::from_le_bytes([ + a.unwrap(), + b.unwrap(), + c.unwrap(), + d.unwrap(), + ])) + } + fn read_string(len: usize, data: &mut dyn Iterator) -> Result { + let mut s = String::new(); + for _ in 0..len { + if let Some(c) = data.next() { + s.push(c as char); + } else { + return Err(ParseError::DataEmpty); + }; + } + Ok(s) + } + fn read_name(data: &mut dyn Iterator) -> Result { + let name: [Option; 8] = [ + data.next(), + data.next(), + data.next(), + data.next(), + data.next(), + data.next(), + data.next(), + data.next(), + ]; + + if name.contains(&None) { + return Err(ParseError::DataEmpty); + } + + Ok(NAME::new(u64::from_le_bytes(name.map(|v| v.unwrap())))) + } + + /* READ ISOBUS OBJECTS */ + + fn read_working_set( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = WorkingSet { + id, + background_colour: Self::read_u8(data)?.into(), + selectable: Self::read_bool(data)?, + active_mask: Self::read_u16(data)?.try_into()?, + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + language_codes: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + for _ in 0..o.language_codes.capacity() { + o.language_codes.push(Self::read_string(2, data)?) + } + + Ok(Object::WorkingSet(o)) + } + + fn read_data_mask( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = DataMask { + id, + background_colour: Self::read_u8(data)?, + soft_key_mask: Self::read_u16(data)?.try_into()?, + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::DataMask(o)) + } + + fn read_alarm_mask( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = AlarmMask { + id, + background_colour: Self::read_u8(data)?, + soft_key_mask: Self::read_u16(data)?.try_into()?, + priority: Self::read_u8(data)?, + acoustic_signal: Self::read_u8(data)?, + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::AlarmMask(o)) + } + + fn read_container( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = Container { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + hidden: Self::read_bool(data)?, + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::Container(o)) + } + + fn read_soft_key_mask( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = SoftKeyMask { + id, + background_colour: Self::read_u8(data)?, + objects: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.objects + .extend(Self::read_objects(data, o.objects.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::SoftKeyMask(o)) + } + + fn read_key(id: ObjectId, data: &mut dyn Iterator) -> Result { + let mut o = Key { + id, + background_colour: Self::read_u8(data)?, + key_code: Self::read_u8(data)?, + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::Key(o)) + } + + fn read_button(id: ObjectId, data: &mut dyn Iterator) -> Result { + let mut o = Button { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + background_colour: Self::read_u8(data)?, + border_colour: Self::read_u8(data)?, + key_code: Self::read_u8(data)?, + options: Self::read_u8(data)?.into(), + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::Button(o)) + } + + fn read_input_boolean( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = InputBoolean { + id, + background_colour: Self::read_u8(data)?, + width: Self::read_u16(data)?, + foreground_colour: Self::read_u16(data)?.try_into()?, + variable_reference: Self::read_u16(data)?.try_into()?, + value: Self::read_bool(data)?, + enabled: Self::read_bool(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::InputBoolean(o)) + } + + fn read_input_string( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = InputString { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + background_colour: Self::read_u8(data)?, + font_attributes: Self::read_u16(data)?.try_into()?, + input_attributes: Self::read_u16(data)?.try_into()?, + options: Self::read_u8(data)?.into(), + variable_reference: Self::read_u16(data)?.try_into()?, + justification: Self::read_u8(data)?.into(), + value: Self::read_string(Self::read_u8(data)?.into(), data)?, + enabled: Self::read_bool(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::InputString(o)) + } + + fn read_input_number( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = InputNumber { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + background_colour: Self::read_u8(data)?, + font_attributes: Self::read_u16(data)?.try_into()?, + options: Self::read_u8(data)?.into(), + variable_reference: Self::read_u16(data)?.try_into()?, + value: Self::read_u32(data)?, + min_value: Self::read_u32(data)?, + max_value: Self::read_u32(data)?, + offset: Self::read_i32(data)?, + scale: Self::read_f32(data)?, + nr_of_decimals: Self::read_u8(data)?, + format: Self::read_bool(data)?.into(), + justification: Self::read_u8(data)?.into(), + options2: Self::read_u8(data)?.into(), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::InputNumber(o)) + } + + fn read_input_list( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = InputList { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + variable_reference: Self::read_u16(data)?.try_into()?, + value: Self::read_u8(data)?, + list_items: Vec::with_capacity(Self::read_u8(data)?.into()), + options: Self::read_u8(data)?.into(), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.list_items + .extend(Self::read_objects(data, o.list_items.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::InputList(o)) + } + + fn read_output_string( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = OutputString { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + background_colour: Self::read_u8(data)?, + font_attributes: Self::read_u16(data)?.try_into()?, + options: Self::read_u8(data)?.into(), + variable_reference: Self::read_u16(data)?.try_into()?, + justification: Self::read_u8(data)?.into(), + value: Self::read_string(Self::read_u16(data)?.into(), data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputString(o)) + } + + fn read_output_number( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = OutputNumber { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + background_colour: Self::read_u8(data)?, + font_attributes: Self::read_u16(data)?.try_into()?, + options: Self::read_u8(data)?.into(), + variable_reference: Self::read_u16(data)?.try_into()?, + value: Self::read_u32(data)?, + offset: Self::read_i32(data)?, + scale: Self::read_f32(data)?, + nr_of_decimals: Self::read_u8(data)?, + format: Self::read_bool(data)?.into(), + justification: Self::read_u8(data)?.into(), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputNumber(o)) + } + + fn read_output_line( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = OutputLine { + id, + line_attributes: Self::read_u16(data)?.try_into()?, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + line_direction: Self::read_u8(data)?.into(), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputLine(o)) + } + + fn read_output_rectangle( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = OutputRectangle { + id, + line_attributes: Self::read_u16(data)?.try_into()?, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + line_suppression: Self::read_u8(data)?, + fill_attributes: Self::read_u16(data)?.try_into()?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputRectangle(o)) + } + + fn read_output_ellipse( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = OutputEllipse { + id, + line_attributes: Self::read_u16(data)?.try_into()?, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + ellipse_type: Self::read_u8(data)?, + start_angle: Self::read_u8(data)?, + end_angle: Self::read_u8(data)?, + fill_attributes: Self::read_u16(data)?.try_into()?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputEllipse(o)) + } + + fn read_output_polygon( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = OutputPolygon { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + line_attributes: Self::read_u16(data)?.try_into()?, + fill_attributes: Self::read_u16(data)?.try_into()?, + polygon_type: Self::read_u8(data)?, + points: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.points + .extend(Self::read_points(data, o.points.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputPolygon(o)) + } + + fn read_output_meter( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = OutputMeter { + id, + width: Self::read_u16(data)?, + needle_colour: Self::read_u8(data)?, + border_colour: Self::read_u8(data)?, + arc_and_tick_colour: Self::read_u8(data)?, + options: Self::read_u8(data)?.into(), + nr_of_ticks: Self::read_u8(data)?, + start_angle: Self::read_u8(data)?, + end_angle: Self::read_u8(data)?, + min_value: Self::read_u16(data)?, + max_value: Self::read_u16(data)?, + variable_reference: Self::read_u16(data)?.try_into()?, + value: Self::read_u16(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputMeter(o)) + } + + fn read_output_linear_bar_graph( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = OutputLinearBarGraph { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + colour: Self::read_u8(data)?, + target_line_colour: Self::read_u8(data)?, + options: Self::read_u8(data)?.into(), + nr_of_ticks: Self::read_u8(data)?, + min_value: Self::read_u16(data)?, + max_value: Self::read_u16(data)?, + variable_reference: Self::read_u16(data)?.try_into()?, + value: Self::read_u16(data)?, + target_value_variable_reference: Self::read_u16(data)?.try_into()?, + target_value: Self::read_u16(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputLinearBarGraph(o)) + } + + fn read_output_arched_bar_graph( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = OutputArchedBarGraph { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + colour: Self::read_u8(data)?, + target_line_colour: Self::read_u8(data)?, + options: Self::read_u8(data)?.into(), + start_angle: Self::read_u8(data)?, + end_angle: Self::read_u8(data)?, + bar_graph_width: Self::read_u16(data)?, + min_value: Self::read_u16(data)?, + max_value: Self::read_u16(data)?, + variable_reference: Self::read_u16(data)?.try_into()?, + value: Self::read_u16(data)?, + target_value_variable_reference: Self::read_u16(data)?.try_into()?, + target_value: Self::read_u16(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputArchedBarGraph(o)) + } + + fn read_picture_graphic( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = PictureGraphic { + id, + width: Self::read_u16(data)?, + actual_width: Self::read_u16(data)?, + actual_height: Self::read_u16(data)?, + format: Self::read_u8(data)?, + options: Self::read_u8(data)?.into(), + transparency_colour: Self::read_u8(data)?, + data: Vec::with_capacity(Self::read_u32(data)? as usize), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.data.extend(Self::read_bytes(data, o.data.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::PictureGraphic(o)) + } + + fn read_number_variable( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let o = NumberVariable { + id, + value: Self::read_u32(data)?, + }; + + Ok(Object::NumberVariable(o)) + } + + fn read_string_variable( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let o = StringVariable { + id, + value: Self::read_string(Self::read_u16(data)?.into(), data)?, + }; + + Ok(Object::StringVariable(o)) + } + + fn read_font_attributes( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = FontAttributes { + id, + font_colour: Self::read_u8(data)?, + font_size: Self::read_u8(data)?, + font_type: Self::read_u8(data)?, + font_style: Self::read_u8(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::FontAttributes(o)) + } + + fn read_line_attributes( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = LineAttributes { + id, + line_colour: Self::read_u8(data)?, + line_width: Self::read_u8(data)?, + line_art: Self::read_u16(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::LineAttributes(o)) + } + + fn read_fill_attributes( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = FillAttributes { + id, + fill_type: Self::read_u8(data)?, + fill_colour: Self::read_u8(data)?, + fill_pattern: Self::read_u16(data)?.try_into()?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::FillAttributes(o)) + } + + fn read_input_attributes( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = InputAttributes { + id, + validation_type: Self::read_u8(data)?, + validation_string: Self::read_string(Self::read_u8(data)?.into(), data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::InputAttributes(o)) + } + + fn read_object_pointer( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let o = ObjectPointer { + id, + value: Self::read_u16(data)?.try_into()?, + }; + + Ok(Object::ObjectPointer(o)) + } + + fn read_macro(id: ObjectId, data: &mut dyn Iterator) -> Result { + let mut o = Macro { + id, + commands: Vec::with_capacity(Self::read_u16(data)?.into()), + }; + + o.commands + .extend(Self::read_bytes(data, o.commands.capacity())?); + + Ok(Object::Macro(o)) + } + + fn read_auxiliary_function_type1( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = AuxiliaryFunctionType1 { + id, + background_colour: Self::read_u8(data)?, + function_type: Self::read_u8(data)?, + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + + Ok(Object::AuxiliaryFunctionType1(o)) + } + + fn read_auxiliary_input_type1( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = AuxiliaryInputType1 { + id, + background_colour: Self::read_u8(data)?, + function_type: Self::read_u8(data)?, + input_id: Self::read_u8(data)?, + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + + Ok(Object::AuxiliaryInputType1(o)) + } + + fn read_auxiliary_function_type2( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = AuxiliaryFunctionType2 { + id, + background_colour: Self::read_u8(data)?, + function_attributes: Self::read_u8(data)?, + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + + Ok(Object::AuxiliaryFunctionType2(o)) + } + + fn read_auxiliary_input_type2( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = AuxiliaryInputType2 { + id, + background_colour: Self::read_u8(data)?, + function_attributes: Self::read_u8(data)?, + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + + Ok(Object::AuxiliaryInputType2(o)) + } + + fn read_auxiliary_control_designator_type2( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let o = AuxiliaryControlDesignatorType2 { + id, + pointer_type: Self::read_u8(data)?, + auxiliary_object_id: Self::read_u16(data)?.try_into()?, + }; + + Ok(Object::AuxiliaryControlDesignatorType2(o)) + } + + fn read_window_mask( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = WindowMask { + id, + cell_format: Self::read_u16(data)?.into(), + window_type: Self::read_u8(data)?.into(), + background_colour: Self::read_u8(data)?, + options: Self::read_u8(data)?.into(), + name: Self::read_u16(data)?.try_into()?, + window_title: Self::read_u16(data)?.try_into()?, + window_icon: Self::read_u16(data)?.try_into()?, + objects: Vec::with_capacity(Self::read_u8(data)?.into()), + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.objects + .extend(Self::read_objects(data, o.objects.capacity())?); + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::WindowMask(o)) + } + + fn read_key_group( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = KeyGroup { + id, + options: Self::read_u8(data)?.into(), + name: Self::read_u16(data)?.try_into()?, + key_group_icon: Self::read_u16(data)?.try_into()?, + objects: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.objects + .extend(Self::read_objects(data, o.objects.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::KeyGroup(o)) + } + + fn read_graphics_context( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let o = GraphicsContext { + id, + viewport_width: Self::read_u16(data)?, + viewport_height: Self::read_u16(data)?, + viewport_x: Self::read_i16(data)?, + viewport_y: Self::read_i16(data)?, + canvas_width: Self::read_u16(data)?, + canvas_height: Self::read_u16(data)?, + viewport_zoom: Self::read_f32(data)?, + graphics_cursor_x: Self::read_i16(data)?, + graphics_cursor_y: Self::read_i16(data)?, + foreground_colour: Self::read_u8(data)?, + background_colour: Self::read_u8(data)?, + font_attributes_object: Self::read_u16(data)?.try_into()?, + line_attributes_object: Self::read_u16(data)?.try_into()?, + fill_attributes_object: Self::read_u16(data)?.try_into()?, + format: Self::read_u8(data)?.into(), + options: Self::read_u8(data)?.into(), + transparency_colour: Self::read_u8(data)?, + }; + Ok(Object::GraphicsContext(o)) + } + + fn read_output_list( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = OutputList { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + variable_reference: Self::read_u16(data)?.try_into()?, + value: Self::read_u8(data)?, + list_items: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.list_items + .extend(Self::read_objects(data, o.list_items.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::OutputList(o)) + } + + fn read_extended_input_attributes( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let o = ExtendedInputAttributes { + id, + validation_type: Self::read_u8(data)?.into(), + code_planes: Self::read_code_planes(data)?, + }; + + Ok(Object::ExtendedInputAttributes(o)) + } + + fn read_colour_map( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = ColourMap { + id, + colour_map: Vec::with_capacity(Self::read_u16(data)?.into()), + }; + + o.colour_map + .extend(Self::read_bytes(data, o.colour_map.capacity())?); + + Ok(Object::ColourMap(o)) + } + + fn read_object_label_reference_list( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = ObjectLabelReferenceList { + id, + object_labels: Vec::with_capacity(Self::read_u16(data)?.into()), + }; + + o.object_labels + .extend(Self::read_object_labels(data, o.object_labels.capacity())?); + + Ok(Object::ObjectLabelReferenceList(o)) + } + + fn read_external_object_definition( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = ExternalObjectDefinition { + id, + options: Self::read_u8(data)?.into(), + name: Self::read_name(data)?, + objects: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.objects + .extend(Self::read_objects(data, o.objects.capacity())?); + + Ok(Object::ExternalObjectDefinition(o)) + } + + fn read_external_reference_name( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let o = ExternalReferenceName { + id, + options: Self::read_u8(data)?.into(), + name: Self::read_name(data)?, + }; + + Ok(Object::ExternalReferenceName(o)) + } + + fn read_external_object_pointer( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let o = ExternalObjectPointer { + id, + default_object_id: Self::read_u16(data)?.try_into()?, + external_reference_name_id: Self::read_u16(data)?.try_into()?, + external_object_id: Self::read_u16(data)?.try_into()?, + }; + + Ok(Object::ExternalObjectPointer(o)) + } + + fn read_animation( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = Animation { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + refresh_interval: Self::read_u16(data)?, + value: Self::read_u8(data)?, + enabled: Self::read_bool(data)?, + first_child_index: Self::read_u8(data)?, + last_child_index: Self::read_u8(data)?, + default_child_index: Self::read_u8(data)?, + options: Self::read_u8(data)?.into(), + object_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.object_refs + .extend(Self::read_object_refs(data, o.object_refs.capacity())?); + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::Animation(o)) + } + + fn read_colour_palette( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = ColourPalette { + id, + options: Self::read_u8(data)?.into(), + colours: Vec::with_capacity(Self::read_u16(data)?.into()), + }; + + o.colours + .extend(Self::read_colours(data, o.colours.capacity())?); + + Ok(Object::ColourPalette(o)) + } + + fn read_graphic_data( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = GraphicData { + id, + format: Self::read_u8(data)?, + data: Vec::with_capacity(Self::read_u32(data)?.try_into().unwrap()), + }; + + o.data.extend(Self::read_bytes(data, o.data.capacity())?); + + Ok(Object::GraphicData(o)) + } + + fn read_working_set_special_controls( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = WorkingSetSpecialControls { + id, + id_of_colour_map: Self::read_u16(data)?.try_into()?, + id_of_colour_palette: Self::read_u16(data)?.try_into()?, + language_pairs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.language_pairs.extend(Self::read_language_pairs( + data, + o.language_pairs.capacity(), + )?); + + Ok(Object::WorkingSetSpecialControls(o)) + } + + fn read_scaled_graphic( + id: ObjectId, + data: &mut dyn Iterator, + ) -> Result { + let mut o = ScaledGraphic { + id, + width: Self::read_u16(data)?, + height: Self::read_u16(data)?, + scale_type: Self::read_u8(data)?, + options: Self::read_u8(data)?.into(), + value: Self::read_u16(data)?, + macro_refs: Vec::with_capacity(Self::read_u8(data)?.into()), + }; + + o.macro_refs + .extend(Self::read_macro_refs(data, o.macro_refs.capacity())?); + + Ok(Object::ScaledGraphic(o)) + } +} + +#[cfg(test)] +mod tests { + use crate::object_pool::object::{Object, WorkingSet}; + use crate::object_pool::object_attributes::{ObjectRef, Point}; + use crate::object_pool::object_id::ObjectId; + use crate::object_pool::{Colour, ObjectPool, ObjectType}; + use std::vec::IntoIter; + + fn read_id_type(data: &mut dyn Iterator) -> ObjectId { + let id = Object::read_u16(data) + .unwrap_or_else(|_| panic!("Failed to read object ID",)) + .try_into() + .unwrap_or_else(|why| panic!("Failed to convert object ID: {:#?}", why)); + + let _object_type: ObjectType = Object::read_u8(data) + .unwrap_or_else(|_| panic!("Failed to read object type",)) + .try_into() + .unwrap_or_else(|_| panic!("Failed to read object type",)); + + id + } + + #[test] + fn read_working_set_test() { + let mut data: IntoIter = vec![ + 0x34, 0x12, //Object ID + 0x00, //Type + 0xF0, //Background colour + 0x01, //Selectable + 0x00, 0x00, //Active mask + 0x02, //Number of object references + 0x00, //Number of macro references + 0x00, //Number of language codes + 0xF1, 0x00, // Object ID reference 1 + 0x7B, 0x00, // X Location reference 1 + 0xC8, 0x01, // Y Location reference 1 + 0xF2, 0x00, // Object ID reference 2 + 0x15, 0x03, // X Location reference 2 + 0x0C, 0x00, // Y Location reference 2 + 0x00, // Event ID reference 1 + 0x00, // Macro ID reference 1 + 0x00, // Event ID reference 2 + 0x00, // Macro ID reference 2 + 0x00, 0x00, // Language code 1 + 0x00, 0x00, // Language code 2 + ] + .into_iter(); + + let id = read_id_type(&mut data); + + let mut pool = ObjectPool::new(); + pool.add( + Object::read_working_set(id, &mut data) + .unwrap_or_else(|why| panic!("Failed to read working set: {:?}", why)), + ); + + let _working_set_act = pool + .working_set_object() + .unwrap_or_else(|| panic!("Failed to get working set of object pool",)); + + let _working_set_exp = WorkingSet { + id, + background_colour: Colour::new_by_id(0xF0), + selectable: true, + active_mask: ObjectId::default(), + object_refs: vec![ + ObjectRef { + id: ObjectId::new(0xF1).unwrap(), + offset: Point { x: 123, y: 456 }, + }, + ObjectRef { + id: ObjectId::new(0xF2).unwrap(), + offset: Point { x: 789, y: 12 }, + }, + ], + macro_refs: vec![], + language_codes: vec![], + }; + + assert_eq!(*_working_set_act, _working_set_exp); + } +} diff --git a/src/object_pool/vt_version.rs b/src/object_pool/vt_version.rs new file mode 100644 index 0000000..16410ab --- /dev/null +++ b/src/object_pool/vt_version.rs @@ -0,0 +1,45 @@ +use crate::object_pool::ParseError; +use crate::object_pool::ParseError::UnknownObjectType; + +#[derive(Debug, Default)] +pub enum VtVersion { + Version0, + Version1, + Version2, + #[default] + Version3, + Version4, + Version5, + Version6, +} + +impl From for u8 { + fn from(vt_version: VtVersion) -> Self { + match vt_version { + VtVersion::Version0 => 0, + VtVersion::Version1 => 1, + VtVersion::Version2 => 2, + VtVersion::Version3 => 3, + VtVersion::Version4 => 4, + VtVersion::Version5 => 5, + VtVersion::Version6 => 6, + } + } +} + +impl TryFrom for VtVersion { + type Error = ParseError; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(VtVersion::Version0), + 1 => Ok(VtVersion::Version1), + 2 => Ok(VtVersion::Version2), + 3 => Ok(VtVersion::Version3), + 4 => Ok(VtVersion::Version4), + 5 => Ok(VtVersion::Version5), + 6 => Ok(VtVersion::Version6), + _ => Err(UnknownObjectType), + } + } +} diff --git a/src/object_pool/writer.rs b/src/object_pool/writer.rs new file mode 100644 index 0000000..c2edb9d --- /dev/null +++ b/src/object_pool/writer.rs @@ -0,0 +1,778 @@ +use super::*; +use crate::object_pool::colour::Colour; +use crate::object_pool::object::{ + AlarmMask, Animation, AuxiliaryControlDesignatorType2, AuxiliaryFunctionType1, + AuxiliaryFunctionType2, AuxiliaryInputType1, AuxiliaryInputType2, Button, CharacterRange, + CodePlane, ColourMap, ColourPalette, Container, DataMask, ExtendedInputAttributes, + ExternalObjectDefinition, ExternalObjectPointer, ExternalReferenceName, FillAttributes, + FontAttributes, GraphicData, GraphicsContext, InputAttributes, InputBoolean, InputList, + InputNumber, InputString, Key, KeyGroup, LineAttributes, Macro, NumberVariable, Object, + ObjectLabelReferenceList, ObjectPointer, OutputArchedBarGraph, OutputEllipse, OutputLine, + OutputLinearBarGraph, OutputList, OutputMeter, OutputNumber, OutputPolygon, OutputRectangle, + OutputString, PictureGraphic, ScaledGraphic, SoftKeyMask, StringVariable, WindowMask, + WorkingSet, WorkingSetSpecialControls, +}; +use crate::object_pool::object_attributes::{MacroRef, ObjectLabel, ObjectRef, Point}; +use crate::object_pool::object_id::ObjectId; + +impl Object { + pub fn write(&self) -> Vec { + let mut data = Vec::new(); + + match self { + Object::WorkingSet(o) => Self::write_working_set(&mut data, o), + Object::DataMask(o) => Self::write_data_mask(&mut data, o), + Object::AlarmMask(o) => Self::write_alarm_mask(&mut data, o), + Object::Container(o) => Self::write_container(&mut data, o), + Object::SoftKeyMask(o) => Self::write_soft_key_mask(&mut data, o), + Object::Key(o) => Self::write_key(&mut data, o), + Object::Button(o) => Self::write_button(&mut data, o), + Object::InputBoolean(o) => Self::write_input_boolean(&mut data, o), + Object::InputString(o) => Self::write_input_string(&mut data, o), + Object::InputNumber(o) => Self::write_input_number(&mut data, o), + Object::InputList(o) => Self::write_input_list(&mut data, o), + Object::OutputString(o) => Self::write_output_string(&mut data, o), + Object::OutputNumber(o) => Self::write_output_number(&mut data, o), + Object::OutputLine(o) => Self::write_output_line(&mut data, o), + Object::OutputRectangle(o) => Self::write_output_rectangle(&mut data, o), + Object::OutputEllipse(o) => Self::write_output_ellipse(&mut data, o), + Object::OutputPolygon(o) => Self::write_output_polygon(&mut data, o), + Object::OutputMeter(o) => Self::write_output_meter(&mut data, o), + Object::OutputLinearBarGraph(o) => Self::write_output_linear_bar_graph(&mut data, o), + Object::OutputArchedBarGraph(o) => Self::write_output_arched_bar_graph(&mut data, o), + Object::PictureGraphic(o) => Self::write_picture_graphic(&mut data, o), + Object::NumberVariable(o) => Self::write_number_variable(&mut data, o), + Object::StringVariable(o) => Self::write_string_variable(&mut data, o), + Object::FontAttributes(o) => Self::write_font_attributes(&mut data, o), + Object::LineAttributes(o) => Self::write_line_attributes(&mut data, o), + Object::FillAttributes(o) => Self::write_fill_attributes(&mut data, o), + Object::InputAttributes(o) => Self::write_input_attributes(&mut data, o), + Object::ObjectPointer(o) => Self::write_object_pointer(&mut data, o), + Object::Macro(o) => Self::write_macro(&mut data, o), + Object::AuxiliaryFunctionType1(o) => Self::write_auxiliary_function_type1(&mut data, o), + Object::AuxiliaryInputType1(o) => Self::write_auxiliary_input_type1(&mut data, o), + Object::AuxiliaryFunctionType2(o) => Self::write_auxiliary_function_type2(&mut data, o), + Object::AuxiliaryInputType2(o) => Self::write_auxiliary_input_type2(&mut data, o), + Object::AuxiliaryControlDesignatorType2(o) => { + Self::write_auxiliary_control_designator_type2(&mut data, o) + } + Object::WindowMask(o) => Self::write_window_mask(&mut data, o), + Object::KeyGroup(o) => Self::write_key_group(&mut data, o), + Object::GraphicsContext(o) => Self::write_graphics_context(&mut data, o), + Object::OutputList(o) => Self::write_output_list(&mut data, o), + Object::ExtendedInputAttributes(o) => { + Self::write_extended_input_attributes(&mut data, o) + } + Object::ColourMap(o) => Self::write_colour_map(&mut data, o), + Object::ObjectLabelReferenceList(o) => { + Self::write_object_label_reference_list(&mut data, o) + } + Object::ExternalObjectDefinition(o) => { + Self::write_external_object_definition(&mut data, o) + } + Object::ExternalReferenceName(o) => Self::write_external_reference_name(&mut data, o), + Object::ExternalObjectPointer(o) => Self::write_external_object_pointer(&mut data, o), + Object::Animation(o) => Self::write_animation(&mut data, o), + Object::ColourPalette(o) => Self::write_colour_palette(&mut data, o), + Object::GraphicData(o) => Self::write_graphic_data(&mut data, o), + Object::WorkingSetSpecialControls(o) => { + Self::write_working_set_special_controls(&mut data, o) + } + Object::ScaledGraphic(o) => Self::write_scaled_graphic(&mut data, o), + } + + data + } + + fn write_objects(data: &mut Vec, objects: &Vec) { + for d in objects { + Self::write_u16(data, *d); + } + } + fn write_object_refs(data: &mut Vec, object_refs: &Vec) { + for d in object_refs { + Self::write_u16(data, d.id); + Self::write_i16(data, d.offset.x); + Self::write_i16(data, d.offset.y); + } + } + fn write_macro_refs(data: &mut Vec, macro_refs: &Vec) { + for d in macro_refs { + Self::write_u8(data, d.event_id); + Self::write_u8(data, d.macro_id); + } + } + fn write_bytes(data: &mut Vec, bytes: &Vec) { + for d in bytes { + Self::write_u8(data, *d); + } + } + fn write_language_codes(data: &mut Vec, language_codes: &Vec) { + for d in language_codes { + Self::write_string(data, d); + } + } + fn write_points(data: &mut Vec, points: &Vec>) { + for d in points { + Self::write_u16(data, d.x); + Self::write_u16(data, d.y); + } + } + fn write_colours(data: &mut Vec, colours: &Vec) { + for d in colours { + Self::write_u8(data, d.b); + Self::write_u8(data, d.g); + Self::write_u8(data, d.r); + Self::write_u8(data, d.a); + } + } + fn write_object_labels(data: &mut Vec, object_labels: &Vec) { + for d in object_labels { + Self::write_u16(data, d.id); + Self::write_u16(data, d.string_variable_reference); + Self::write_u8(data, d.font_type); + Self::write_u16(data, d.graphic_representation); + } + } + fn write_language_pairs(data: &mut Vec, language_pairs: &Vec<(String, String)>) { + for d in language_pairs { + Self::write_string(data, &d.0); + Self::write_string(data, &d.1); + } + } + + fn write_character_ranges(data: &mut Vec, character_ranges: &Vec) { + for character_range in character_ranges { + Self::write_u16(data, character_range.first_character); + Self::write_u16(data, character_range.last_character); + } + } + + fn write_code_planes(data: &mut Vec, code_planes: &Vec) { + Self::write_u8(data, code_planes.len() as u8); + + for code_plane in code_planes { + Self::write_u8(data, code_plane.number); + Self::write_u8(data, code_plane.character_ranges.len() as u8); + Self::write_character_ranges(data, &code_plane.character_ranges); + } + } + + fn write_u8(data: &mut Vec, val: impl Into) { + let val: u8 = val.into(); + data.push(val); + } + fn write_u16(data: &mut Vec, val: impl Into) { + let val: u16 = val.into(); + data.extend(val.to_le_bytes()); + } + fn write_i16(data: &mut Vec, val: impl Into) { + let val: i16 = val.into(); + data.extend(val.to_le_bytes()); + } + fn write_u32(data: &mut Vec, val: impl Into) { + let val: u32 = val.into(); + data.extend(val.to_le_bytes()); + } + fn write_i32(data: &mut Vec, val: impl Into) { + let val: i32 = val.into(); + data.extend(val.to_le_bytes()); + } + fn write_f32(data: &mut Vec, val: impl Into) { + let val: f32 = val.into(); + data.extend(val.to_le_bytes()); + } + fn write_string(data: &mut Vec, val: impl Into) { + let val: String = val.into(); + data.extend(val.as_bytes()); + } + fn write_name(data: &mut Vec, val: impl Into) { + let val: NAME = val.into(); + data.extend::<[u8; 8]>(val.into()); + } + fn write_working_set(data: &mut Vec, o: &WorkingSet) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::WorkingSet); + Self::write_u8(data, o.background_colour); + Self::write_u8(data, o.selectable); + Self::write_u16(data, o.active_mask); + Self::write_u8(data, o.object_refs.len() as u8); + Self::write_u8(data, o.macro_refs.len() as u8); + Self::write_u8(data, o.language_codes.len() as u8); + + Self::write_object_refs(data, &o.object_refs); + Self::write_macro_refs(data, &o.macro_refs); + Self::write_language_codes(data, &o.language_codes); + } + fn write_data_mask(data: &mut Vec, o: &DataMask) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::DataMask); + Self::write_u8(data, o.background_colour); + Self::write_u16(data, o.soft_key_mask); + Self::write_u8(data, o.object_refs.len() as u8); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_object_refs(data, &o.object_refs); + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_alarm_mask(data: &mut Vec, o: &AlarmMask) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::AlarmMask); + Self::write_u8(data, o.background_colour); + Self::write_u16(data, o.soft_key_mask); + Self::write_u8(data, o.priority); + Self::write_u8(data, o.acoustic_signal); + Self::write_u8(data, o.object_refs.len() as u8); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_object_refs(data, &o.object_refs); + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_container(data: &mut Vec, o: &Container) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::Container); + Self::write_u16(data, o.width); + Self::write_u16(data, o.height); + Self::write_u8(data, o.hidden); + Self::write_u8(data, o.object_refs.len() as u8); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_object_refs(data, &o.object_refs); + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_soft_key_mask(data: &mut Vec, o: &SoftKeyMask) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::SoftKeyMask); + Self::write_u8(data, o.background_colour); + Self::write_u8(data, o.objects.len() as u8); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_objects(data, &o.objects); + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_key(data: &mut Vec, o: &Key) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::Key); + Self::write_u8(data, o.background_colour); + Self::write_u8(data, o.key_code); + Self::write_u8(data, o.object_refs.len() as u8); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_object_refs(data, &o.object_refs); + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_button(data: &mut Vec, o: &Button) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::Button); + Self::write_u16(data, o.width); + Self::write_u16(data, o.height); + Self::write_u8(data, o.background_colour); + Self::write_u8(data, o.border_colour); + Self::write_u8(data, o.key_code); + Self::write_u8(data, o.options); + Self::write_u8(data, o.object_refs.len() as u8); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_object_refs(data, &o.object_refs); + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_input_boolean(data: &mut Vec, o: &InputBoolean) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::InputBoolean); + Self::write_u8(data, o.background_colour); + Self::write_u16(data, o.width); + Self::write_u16(data, o.foreground_colour); + Self::write_u16(data, o.variable_reference); + Self::write_u8(data, o.value); + Self::write_u8(data, o.enabled); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_input_string(data: &mut Vec, o: &InputString) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::InputString); + Self::write_u16(data, o.width); + Self::write_u16(data, o.height); + Self::write_u8(data, o.background_colour); + Self::write_u16(data, o.font_attributes); + Self::write_u16(data, o.input_attributes); + Self::write_u8(data, o.options); + Self::write_u16(data, o.variable_reference); + Self::write_u8(data, o.justification); + Self::write_string(data, &o.value); + Self::write_u8(data, o.enabled); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_input_number(data: &mut Vec, o: &InputNumber) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::InputNumber); + Self::write_u16(data, o.width); + Self::write_u16(data, o.height); + Self::write_u8(data, o.background_colour); + Self::write_u16(data, o.font_attributes); + Self::write_u8(data, o.options); + Self::write_u16(data, o.variable_reference); + Self::write_u32(data, o.value); + Self::write_u32(data, o.min_value); + Self::write_u32(data, o.max_value); + Self::write_i32(data, o.offset); + Self::write_f32(data, o.scale); + Self::write_u8(data, o.nr_of_decimals); + Self::write_u8(data, o.format as u8); + Self::write_u8(data, o.justification); + Self::write_u8(data, o.options2); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_input_list(data: &mut Vec, o: &InputList) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::InputList); + Self::write_u16(data, o.width); + Self::write_u16(data, o.height); + Self::write_u16(data, o.variable_reference); + Self::write_u8(data, o.value); + Self::write_u8(data, o.list_items.len() as u8); + Self::write_u8(data, o.options); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_objects(data, &o.list_items); + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_output_string(data: &mut Vec, o: &OutputString) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::OutputString); + Self::write_u16(data, o.width); + Self::write_u16(data, o.height); + Self::write_u8(data, o.background_colour); + Self::write_u16(data, o.font_attributes); + Self::write_u8(data, o.options); + Self::write_u16(data, o.variable_reference); + Self::write_u8(data, o.justification); + Self::write_u16(data, o.value.len() as u16); + Self::write_string(data, &o.value); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_output_number(data: &mut Vec, o: &OutputNumber) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::OutputNumber); + Self::write_u16(data, o.width); + Self::write_u16(data, o.height); + Self::write_u8(data, o.background_colour); + Self::write_u16(data, o.font_attributes); + Self::write_u8(data, o.options); + Self::write_u16(data, o.variable_reference); + Self::write_u32(data, o.value); + Self::write_i32(data, o.offset); + Self::write_f32(data, o.scale); + Self::write_u8(data, o.nr_of_decimals); + Self::write_u8(data, o.format as u8); + Self::write_u8(data, o.justification); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_output_line(data: &mut Vec, o: &OutputLine) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::OutputLine); + Self::write_u16(data, o.line_attributes); + Self::write_u16(data, o.width); + Self::write_u16(data, o.height); + Self::write_u8(data, o.line_direction); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_output_rectangle(data: &mut Vec, o: &OutputRectangle) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::OutputRectangle); + Self::write_u16(data, o.line_attributes); + Self::write_u16(data, o.width); + Self::write_u16(data, o.height); + Self::write_u8(data, o.line_suppression); + Self::write_u16(data, o.fill_attributes); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_output_ellipse(data: &mut Vec, o: &OutputEllipse) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::OutputEllipse); + Self::write_u16(data, o.line_attributes); + Self::write_u16(data, o.width); + Self::write_u16(data, o.height); + Self::write_u8(data, o.ellipse_type); + Self::write_u8(data, o.start_angle); + Self::write_u8(data, o.end_angle); + Self::write_u16(data, o.fill_attributes); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_output_polygon(data: &mut Vec, o: &OutputPolygon) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::OutputPolygon); + Self::write_u16(data, o.width); + Self::write_u16(data, o.height); + Self::write_u16(data, o.line_attributes); + Self::write_u16(data, o.fill_attributes); + Self::write_u8(data, o.polygon_type); + Self::write_u8(data, o.points.len() as u8); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_points(data, &o.points); + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_output_meter(data: &mut Vec, o: &OutputMeter) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::OutputMeter); + Self::write_u16(data, o.width); + Self::write_u8(data, o.needle_colour); + Self::write_u8(data, o.border_colour); + Self::write_u8(data, o.arc_and_tick_colour); + Self::write_u8(data, o.options); + Self::write_u8(data, o.nr_of_ticks); + Self::write_u8(data, o.start_angle); + Self::write_u8(data, o.end_angle); + Self::write_u16(data, o.min_value); + Self::write_u16(data, o.max_value); + Self::write_u16(data, o.variable_reference); + Self::write_u16(data, o.value); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_output_linear_bar_graph(data: &mut Vec, o: &OutputLinearBarGraph) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::OutputLinearBarGraph); + Self::write_u16(data, o.width); + Self::write_u16(data, o.height); + Self::write_u8(data, o.colour); + Self::write_u8(data, o.target_line_colour); + Self::write_u8(data, o.options); + Self::write_u8(data, o.nr_of_ticks); + Self::write_u16(data, o.min_value); + Self::write_u16(data, o.max_value); + Self::write_u16(data, o.variable_reference); + Self::write_u16(data, o.value); + Self::write_u16(data, o.target_value_variable_reference); + Self::write_u16(data, o.target_value); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_output_arched_bar_graph(data: &mut Vec, o: &OutputArchedBarGraph) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::OutputArchedBarGraph); + Self::write_u16(data, o.width); + Self::write_u16(data, o.height); + Self::write_u8(data, o.colour); + Self::write_u8(data, o.target_line_colour); + Self::write_u8(data, o.options); + Self::write_u8(data, o.start_angle); + Self::write_u8(data, o.end_angle); + Self::write_u16(data, o.bar_graph_width); + Self::write_u16(data, o.min_value); + Self::write_u16(data, o.max_value); + Self::write_u16(data, o.variable_reference); + Self::write_u16(data, o.value); + Self::write_u16(data, o.target_value_variable_reference); + Self::write_u16(data, o.target_value); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_picture_graphic(data: &mut Vec, o: &PictureGraphic) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::PictureGraphic); + Self::write_u16(data, o.width); + Self::write_u16(data, o.actual_width); + Self::write_u16(data, o.actual_height); + Self::write_u8(data, o.format); + Self::write_u8(data, o.options); + Self::write_u8(data, o.transparency_colour); + Self::write_u32(data, o.data.len() as u32); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_bytes(data, &o.data); + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_number_variable(data: &mut Vec, o: &NumberVariable) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::NumberVariable); + Self::write_u32(data, o.value); + } + fn write_string_variable(data: &mut Vec, o: &StringVariable) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::StringVariable); + Self::write_string(data, &o.value); + } + fn write_font_attributes(data: &mut Vec, o: &FontAttributes) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::FontAttributes); + Self::write_u8(data, o.font_colour); + Self::write_u8(data, o.font_size); + Self::write_u8(data, o.font_type); + Self::write_u8(data, o.font_style); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_line_attributes(data: &mut Vec, o: &LineAttributes) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::LineAttributes); + Self::write_u8(data, o.line_colour); + Self::write_u8(data, o.line_width); + Self::write_u16(data, o.line_art); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_fill_attributes(data: &mut Vec, o: &FillAttributes) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::FillAttributes); + Self::write_u8(data, o.fill_type); + Self::write_u8(data, o.fill_colour); + Self::write_u16(data, o.fill_pattern); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_input_attributes(data: &mut Vec, o: &InputAttributes) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::InputAttributes); + Self::write_u8(data, o.validation_type); + Self::write_string(data, &o.validation_string); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_object_pointer(data: &mut Vec, o: &ObjectPointer) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::ObjectPointer); + Self::write_u16(data, o.value); + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::ObjectPointer); + Self::write_u16(data, o.value); + } + fn write_macro(data: &mut Vec, o: &Macro) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::Macro); + Self::write_u16(data, o.commands.len() as u16); + + Self::write_bytes(data, &o.commands); + } + fn write_auxiliary_function_type1(data: &mut Vec, o: &AuxiliaryFunctionType1) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::AuxiliaryFunctionType1); + Self::write_u8(data, o.background_colour); + Self::write_u8(data, o.function_type); + Self::write_u8(data, o.object_refs.len() as u8); + + Self::write_object_refs(data, &o.object_refs); + } + fn write_auxiliary_input_type1(data: &mut Vec, o: &AuxiliaryInputType1) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::AuxiliaryInputType1); + Self::write_u8(data, o.background_colour); + Self::write_u8(data, o.function_type); + Self::write_u8(data, o.input_id); + Self::write_u8(data, o.object_refs.len() as u8); + + Self::write_object_refs(data, &o.object_refs); + } + fn write_auxiliary_function_type2(data: &mut Vec, o: &AuxiliaryFunctionType2) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::AuxiliaryFunctionType2); + Self::write_u8(data, o.background_colour); + Self::write_u8(data, o.function_attributes); + Self::write_u8(data, o.object_refs.len() as u8); + + Self::write_object_refs(data, &o.object_refs); + } + fn write_auxiliary_input_type2(data: &mut Vec, o: &AuxiliaryInputType2) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::AuxiliaryInputType2); + Self::write_u8(data, o.background_colour); + Self::write_u8(data, o.function_attributes); + Self::write_u8(data, o.object_refs.len() as u8); + + Self::write_object_refs(data, &o.object_refs); + } + fn write_auxiliary_control_designator_type2( + data: &mut Vec, + o: &AuxiliaryControlDesignatorType2, + ) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::AuxiliaryControlDesignatorType2); + Self::write_u8(data, o.pointer_type); + Self::write_u16(data, o.auxiliary_object_id); + } + fn write_window_mask(data: &mut Vec, o: &WindowMask) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::WindowMask); + Self::write_u8(data, o.cell_format.size().x); + Self::write_u8(data, o.cell_format.size().y); + Self::write_u8(data, o.window_type); + Self::write_u8(data, o.background_colour); + Self::write_u8(data, o.options); + Self::write_u16(data, o.name); + Self::write_u16(data, o.window_title); + Self::write_u16(data, o.window_icon); + Self::write_u8(data, o.objects.len() as u8); + Self::write_u8(data, o.object_refs.len() as u8); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_objects(data, &o.objects); + Self::write_object_refs(data, &o.object_refs); + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_key_group(data: &mut Vec, o: &KeyGroup) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::KeyGroup); + Self::write_u8(data, o.options); + Self::write_u16(data, o.name); + Self::write_u16(data, o.key_group_icon); + Self::write_u8(data, o.objects.len() as u8); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_objects(data, &o.objects); + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_graphics_context(data: &mut Vec, o: &GraphicsContext) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::GraphicsContext); + Self::write_u16(data, o.viewport_width); + Self::write_u16(data, o.viewport_height); + Self::write_i16(data, o.viewport_x); + Self::write_i16(data, o.viewport_y); + Self::write_u16(data, o.canvas_width); + Self::write_u16(data, o.canvas_height); + Self::write_f32(data, o.viewport_zoom); + Self::write_i16(data, o.graphics_cursor_x); + Self::write_i16(data, o.graphics_cursor_y); + Self::write_u8(data, o.foreground_colour); + Self::write_u8(data, o.background_colour); + Self::write_u16(data, o.font_attributes_object); + Self::write_u16(data, o.line_attributes_object); + Self::write_u16(data, o.fill_attributes_object); + Self::write_u8(data, o.format); + Self::write_u8(data, o.options); + Self::write_u8(data, o.transparency_colour); + } + fn write_output_list(data: &mut Vec, o: &OutputList) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::OutputList); + Self::write_u16(data, o.width); + Self::write_u16(data, o.height); + Self::write_u16(data, o.variable_reference); + Self::write_u8(data, o.value); + Self::write_u8(data, o.list_items.len() as u8); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_objects(data, &o.list_items); + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_extended_input_attributes(data: &mut Vec, o: &ExtendedInputAttributes) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::ExtendedInputAttributes); + Self::write_u8(data, o.validation_type as u8); + Self::write_code_planes(data, &o.code_planes); + } + fn write_colour_map(data: &mut Vec, o: &ColourMap) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::ColourMap); + Self::write_u16(data, o.colour_map.len() as u16); + + Self::write_bytes(data, &o.colour_map); + } + fn write_object_label_reference_list(data: &mut Vec, o: &ObjectLabelReferenceList) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::ObjectLabelReferenceList); + Self::write_u16(data, o.object_labels.len() as u16); + + Self::write_object_labels(data, &o.object_labels); + } + fn write_external_object_definition(data: &mut Vec, o: &ExternalObjectDefinition) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::ExternalObjectDefinition); + Self::write_u8(data, o.options); + Self::write_name(data, o.name); + Self::write_u8(data, o.objects.len() as u8); + + Self::write_objects(data, &o.objects); + } + fn write_external_reference_name(data: &mut Vec, o: &ExternalReferenceName) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::ExternalReferenceName); + Self::write_u8(data, o.options); + Self::write_name(data, o.name); + } + fn write_external_object_pointer(data: &mut Vec, o: &ExternalObjectPointer) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::ExternalObjectPointer); + Self::write_u16(data, o.default_object_id); + Self::write_u16(data, o.external_reference_name_id); + Self::write_u16(data, o.external_object_id); + } + fn write_animation(data: &mut Vec, o: &Animation) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::Animation); + Self::write_u16(data, o.width); + Self::write_u16(data, o.height); + Self::write_u16(data, o.refresh_interval); + Self::write_u8(data, o.value); + Self::write_u8(data, o.enabled); + Self::write_u8(data, o.first_child_index); + Self::write_u8(data, o.last_child_index); + Self::write_u8(data, o.default_child_index); + Self::write_u8(data, o.options); + Self::write_u8(data, o.object_refs.len() as u8); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_object_refs(data, &o.object_refs); + Self::write_macro_refs(data, &o.macro_refs); + } + fn write_colour_palette(data: &mut Vec, o: &ColourPalette) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::ColourPalette); + Self::write_u8(data, o.options); + Self::write_u16(data, o.colours.len() as u16); + + Self::write_colours(data, &o.colours); + } + fn write_graphic_data(data: &mut Vec, o: &GraphicData) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::GraphicData); + Self::write_u8(data, o.format); + Self::write_u32(data, o.data.len() as u32); + + Self::write_bytes(data, &o.data); + } + fn write_working_set_special_controls(data: &mut Vec, o: &WorkingSetSpecialControls) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::WorkingSetSpecialControls); + Self::write_u16(data, o.id_of_colour_map); + Self::write_u16(data, o.id_of_colour_palette); + Self::write_u8(data, o.language_pairs.len() as u8); + + Self::write_language_pairs(data, &o.language_pairs); + } + fn write_scaled_graphic(data: &mut Vec, o: &ScaledGraphic) { + Self::write_u16(data, o.id); + Self::write_u8(data, ObjectType::ScaledGraphic); + Self::write_u16(data, o.width); + Self::write_u16(data, o.height); + Self::write_u8(data, o.scale_type); + Self::write_u8(data, o.options); + Self::write_u16(data, o.value); + Self::write_u8(data, o.macro_refs.len() as u8); + + Self::write_macro_refs(data, &o.macro_refs); + } +}