# Action Mapping Binary Structure - Complete Guide ## Summary Based on analysis of TestMKS_original.set vs TestMKS_added_mapping.set, this document explains how action mappings are stored and how to programmatically add thousands of them. ## Binary Structure ### Overall Format ``` MARKER SECTION: ├─ 'ules' (4 bytes) - Action mapping marker ├─ Length (4 bytes, little-endian) - Length of marker name/data section └─ Marker Name/Data Section (variable length) ├─ Metadata bytes ├─ Properties (optional, multiple) │ └─ Each property: 01 <.name> └─ Additional metadata ACTION SECTION (follows marker section): ├─ Action Entry 1 │ ├─ Entry number (01 for first, 02 for second, etc.) │ ├─ Metadata: 05 00 00 00 │ ├─ Action data: 07 01 40 │ └─ Additional metadata (varies) ├─ Action Entry 2 │ └─ (same structure) └─ ... NEXT MARKER: └─ 05 'Rules' or next 'ules' marker ``` ### Example 1: Simple Mapping (No Parameters) **Hex Dump (offset 0x41433):** ``` 75 6C 65 73 - 'ules' marker 02 00 00 00 - Length: 2 bytes 00 01 - Marker data (2 bytes) 31 05 00 00 00 - Action entry #1 metadata 07 01 40 - Action marker 0B 00 - Length: 11 bytes (little-endian) 47 53 43 20 50 61 6E 4C 65 66 74 - "GSC PanLeft" ... ``` ### Example 2: Mapping with Parameters **Hex Dump (offset 0x3D90D):** ``` 75 6C 65 73 - 'ules' marker 40 00 00 00 - Length: 64 bytes 00 01 - Start of marker data # Properties within marker data: 01 - Property marker 0B - Name length: 11 2E 53 77 69 74 63 68 4D 6F 64 65 - ".SwitchMode" 00 - Value type: null 01 - Property marker 0C - Name length: 12 2E 56 69 64 65 6F 4F 75 74 70 75 74 - ".VideoOutput" 00 - Value type: null # Then actions follow... ``` ## Property Value Types | Marker | Type | Structure | |--------|------|-----------| | `0x01` | Boolean | `01 ` where value is 00 or 01 | | `0x04` | Integer | `04 ` (4 bytes, little-endian) | | `0x00` | Null | Just `00` | | `0x07` | String | `07 ` | ## Action Entry Format Each action entry consists of: ``` - 01, 02, 03, etc. (sequential) 05 00 00 00 - Metadata (always this sequence) 07 01 40 - Action marker (always this sequence) - 2 bytes, little-endian (length of action string) - UTF-8 encoded action name 04 02 40 21 00 00 00 00 - Additional metadata 04 02 40 40 <4 bytes> - More metadata (varies) ``` ## Key Findings ### 1. File Reorganization When you add a mapping using GeViSoft GUI: - The entire .set file is reorganized - All offsets change - Mappings may be reordered - Net result: +1 mapping but many bytes change This means you **cannot** simply append to the end of the file! ### 2. Insertion Strategy To programmatically add mappings: **Option A: Parse → Modify → Rebuild** 1. Parse the entire .set file 2. Add new mapping to internal structure 3. Regenerate the entire file 4. Write back to disk **Option B: Use GeViSoft API** (if available) 1. Use SetupClient API to modify configuration 2. Let GeViSoft handle file format **Option C: Template-Based** (recommended for bulk) 1. Create template mappings in GUI 2. Export configuration 3. Use find/replace to duplicate with new IDs 4. Import back ### 3. Complexity Factors - Offsets must be recalculated - File structure is tightly packed - No obvious "free space" to insert data - Dependencies between sections unknown - Checksum or validation may exist ## Programmatic Approach ### Step 1: Create Mapping Binary Data ```python def create_action_mapping(actions, parameters=None): """ Generate binary data for an action mapping Args: actions: List of action strings parameters: Dict of parameter_name -> value (optional) Returns: bytes: Complete mapping binary data """ import struct # Build marker name/data section marker_data = bytearray() marker_data.extend(b'\x00\x01') # Base metadata # Add parameters if any if parameters: for name, value in parameters.items(): # Property marker marker_data.append(0x01) # Name with leading dot name_with_dot = f".{name}" name_bytes = name_with_dot.encode('utf-8') marker_data.append(len(name_bytes)) marker_data.extend(name_bytes) # Value if value is None: marker_data.append(0x00) elif isinstance(value, bool): marker_data.append(0x01) marker_data.append(0x01 if value else 0x00) elif isinstance(value, int): marker_data.append(0x04) marker_data.extend(struct.pack('() }; config.AddMapping(mapping); } writer.Write(config, outputFile); ``` 2. **Batch Process via GUI Templates** - Create 1 mapping template in GUI - Export configuration as JSON/XML (if supported) - Programmatically duplicate + modify - Import back 3. **Direct Binary Manipulation** (risky!) - Parse existing file completely - Understand all section dependencies - Insert mappings - Rebuild file with correct offsets ## Next Steps For your use case (adding thousands of mappings), I recommend: 1. **Extend C# Parser** to support WRITING (currently read-only) 2. **Create AddActionMapping() method** in ConfigurationService 3. **Batch add** via gRPC/REST API 4. **Write back** to .set file Would you like me to: - [ ] Create C# writer for .set files - [ ] Build Python script for bulk mapping creation - [ ] Extend the gRPC API to support CREATE operations - [ ] Create a bulk import tool (CSV → action mappings)