app
Adom Library
Public Made by Adomby adom
adom-lbr — the EDA library translator. Bring a component in from any supported EDA tool and convert it to any other (KiCad ⇄ Altium ⇄ EAGLE/Fusion) through one canonical adom-lbr JSON — symbol + footprint + 3D + pin↔pad map. Altium is written natively (no Altium needed). Includes the adom-lbr Manager: browse wiki components and view symbol/footprint/3D + the per-EDA layer stackup.
← Commit history
src/altium_schlib_write.rsdeleted−128@@ -1,128 +0,0 @@-//! Native Altium `.SchLib` WRITER — pure Rust, no Altium. The inverse of the-//! reader: emits an OLE2/CFB container whose streams and records are-//! byte-structurally identical to what real Altium produces (verified by-//! re-reading with this crate's parser and by byte-diffing pin records against-//! manufacturer `.SchLib` files).-//!-//! Container: `/FileHeader` (component list) · `/Storage` (icon placeholder) ·-//! `/\x01Sh33tJ5` (the constant "7262" marker) · `/<part>` storage · `/<part>/Data`-//! (the record stream). Every stream is framed `<u16 len><u16 flags><payload>`.--use anyhow::Result;-use std::io::{Cursor, Write};--/// A schematic pin to emit, in Altium SCH internal units (1 unit = 2.54/2560 mm).-/// `x`/`y` are the pin's connection-end location; Altium Y is up. `rotation` is-/// 0/90/180/270 degrees.-pub struct WritePin {- pub name: String,- pub designator: String,- pub x: i32,- pub y: i32,- pub length: i32,- pub rotation: i32,-}--/// The fixed 26-byte prefix of an Altium pin record (record type `0x02`),-/// captured byte-for-byte from a real manufacturer `.SchLib`. Bytes [14] (pin-/// conglomerate / orientation), [15..17] (length), [17..19] (X) and [19..21] (Y)-/// are overwritten per pin; the rest (owner-part id, electrical defaults, the-/// trailing sentinels) carry through unchanged — which is why generated pins are-/// byte-identical to Altium's own.-const PIN_PREFIX: [u8; 26] = [- 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,- 0x01, 0x04, 0x3a, 0x14, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,-];--fn put_rec(out: &mut Vec<u8>, flags: u16, payload: &[u8]) {- out.extend_from_slice(&(payload.len() as u16).to_le_bytes());- out.extend_from_slice(&flags.to_le_bytes());- out.extend_from_slice(payload);-}--/// Altium length-prefixed (1-byte) string.-fn put_pstr(out: &mut Vec<u8>, s: &str) {- let b = s.as_bytes();- let n = b.len().min(255);- out.push(n as u8);- out.extend_from_slice(&b[..n]);-}--/// A text record (`|KEY=VAL|…`) — payload is the text plus a trailing NUL, the-/// way Altium frames its FileHeader and component header records.-fn put_text(out: &mut Vec<u8>, flags: u16, body: &str) {- let mut p = body.as_bytes().to_vec();- p.push(0);- put_rec(out, flags, &p);-}--/// Deterministic 8-uppercase-letter UniqueID from an index (Altium wants a-/// stable A–Z token per primitive; exact value is cosmetic).-fn uid(i: usize) -> String {- let mut s = String::new();- let mut n = i + 1;- for _ in 0..8 {- s.push((b'A' + (n % 26) as u8) as char);- n = n / 26 + 1;- }- s-}--/// Emit a native `.SchLib` for one component. `body` is the symbol body-/// rectangle (x1,y1,x2,y2) in Altium SCH units. `params` become hidden-/// `RECORD=41` parameters (Manufacturer / MPN / "LCSC Part #" / …) — exactly the-/// fields Altium surfaces in the BOM.-pub fn to_schlib_bytes(- part: &str,- description: &str,- body: (i32, i32, i32, i32),- pins: &[WritePin],- params: &[(String, String)],-) -> Result<Vec<u8>> {- // ----- component Data stream ------ let mut d = Vec::new();- put_text(&mut d, 0, &format!(- "|RECORD=1|LibReference={part}|ComponentDescription={description}|PartCount=1|DisplayModeCount=1|IndexInSheet=-1|OwnerPartId=-1|CurrentPartId=1|LibraryPath=*|SourceLibraryName=*|SheetPartFileName=*|TargetFileName=*|UniqueID={}|AreaColor=11599871|Color=128|PartIDLocked=T|AllPinCount={}",- uid(0), pins.len()));- for (k, (name, val)) in params.iter().enumerate() {- put_text(&mut d, 0, &format!(- "|RECORD=41|IndexInSheet={k}|OwnerPartId=-1|Color=8388608|FontID=1|IsHidden=T|Text={val}|Name={name}|UniqueID={}",- uid(100 + k)));- }- let (lx, ly, cx, cy) = body;- put_text(&mut d, 0, &format!(- "|RECORD=14|IsNotAccesible=T|OwnerPartId=1|Location.X={lx}|Location.Y={ly}|Corner.X={cx}|Corner.Y={cy}|LineWidth=1|Color=128|AreaColor=11599871|IsSolid=T|UniqueID={}",- uid(50)));- for p in pins {- let mut h = PIN_PREFIX.to_vec();- h[14] = (h[14] & !0x03) | (((p.rotation.rem_euclid(360) / 90) & 0x03) as u8);- h[15..17].copy_from_slice(&(p.length as i16).to_le_bytes());- h[17..19].copy_from_slice(&(p.x as i16).to_le_bytes());- h[19..21].copy_from_slice(&(p.y as i16).to_le_bytes());- let mut pl = h;- put_pstr(&mut pl, &p.name);- put_pstr(&mut pl, &p.designator);- put_pstr(&mut pl, "0");- put_pstr(&mut pl, "0");- put_pstr(&mut pl, "");- put_rec(&mut d, 0x0100, &pl);- }-- // ----- FileHeader (the component list) ------ let mut fh = Vec::new();- put_text(&mut fh, 0, &format!(- "|HEADER=Protel for Windows - Schematic Library Editor Binary File Version 5.0|Weight=80|MinorVersion=3|UniqueID=ADOMLBRX|FontIdCount=2|Size1=10|FontName1=Times New Roman|Size2=10|Underline2=T|FontName2=Times New Roman|UseMBCS=T|IsBOC=T|SheetStyle=9|BorderOn=T|SheetNumberSpaceSize=12|AreaColor=16317695|SnapGridOn=T|SnapGridSize=10|VisibleGridOn=T|VisibleGridSize=10|CustomX=18000|CustomY=18000|UseCustomSheet=T|ReferenceZonesOn=T|Display_Unit=0|CompCount=1|LibRef0={part}|CompDescr0={description}|PartCount0=1|AlwaysShowCD=T"));-- let mut storage = Vec::new();- put_text(&mut storage, 0, "|HEADER=Icon storage");-- // ----- assemble the OLE2/CFB container ------ let mut comp = cfb::CompoundFile::create(Cursor::new(Vec::new()))?;- comp.create_stream("/FileHeader")?.write_all(&fh)?;- comp.create_stream("/Storage")?.write_all(&storage)?;- comp.create_stream("/\u{1}Sh33tJ5")?.write_all(b"7262")?;- comp.create_storage(&format!("/{part}"))?;- comp.create_stream(&format!("/{part}/Data"))?.write_all(&d)?;- comp.flush()?;- Ok(comp.into_inner().into_inner())-}