Skip to main content

knx_rs_prod/
lib.rs

1// SPDX-License-Identifier: GPL-3.0-only
2// Copyright (C) 2026 Fabian Schmieder
3
4//! Cross-platform .knxprod generator for KNX ETS product databases.
5//!
6//! Replaces the Windows-only ETS DLLs for generating .knxprod files.
7//! Takes a monolithic KNX product XML (as produced by `OpenKNXproducer`)
8//! and generates a signed .knxprod ZIP archive importable by ETS.
9//!
10//! # Pipeline
11//!
12//! 1. **Parse** — extract metadata (namespace, manufacturer ID, application ID)
13//! 2. **Split** — split monolithic XML into Catalog.xml, Hardware.xml, Application.xml
14//! 3. **Sign** — hash and sign XML files (not yet implemented)
15//! 4. **Package** — ZIP into .knxprod
16//!
17//! # Example
18//!
19//! ```rust,no_run
20//! use std::path::Path;
21//! use knx_rs_prod::generate_knxprod;
22//!
23//! generate_knxprod(
24//!     Path::new("NeoPixel.xml"),
25//!     Path::new("NeoPixel.knxprod"),
26//! ).expect("failed to generate knxprod");
27//! ```
28
29pub mod archive;
30pub mod error;
31pub mod hash;
32pub mod parse;
33pub mod sign;
34pub mod split;
35
36use std::path::Path;
37
38use error::KnxprodError;
39
40/// Generate a .knxprod file from a KNX product XML.
41///
42/// This is the main entry point. It parses the input XML, splits it into
43/// separate files, and packages them into a .knxprod ZIP archive.
44///
45/// # Errors
46///
47/// Returns [`KnxprodError`] if any step fails.
48pub fn generate_knxprod(input: &Path, output: &Path) -> Result<parse::KnxMetadata, KnxprodError> {
49    let xml = std::fs::read_to_string(input).map_err(|e| KnxprodError::io(input, e))?;
50    let metadata = parse::extract_metadata_from_str(&xml)?;
51
52    let temp_dir = tempfile::tempdir().map_err(|e| KnxprodError::io(input, e))?;
53
54    let split_result = split::split_xml(&xml, &metadata, temp_dir.path())?;
55
56    let signed_result = sign::sign_application(&split_result)?;
57
58    archive::create_knxprod(temp_dir.path(), output)?;
59
60    // Update metadata with the new application ID (with correct fingerprint).
61    let new_app_id = signed_result
62        .application
63        .file_stem()
64        .and_then(|s| s.to_str())
65        .unwrap_or(&metadata.application_id)
66        .to_string();
67
68    Ok(parse::KnxMetadata {
69        application_id: new_app_id,
70        ..metadata
71    })
72}