libredwg_sys/lib.rs
1//! Raw FFI bindings to the LibreDWG C sources (a vendored subset of the
2//! real upstream project at `lib/libredwg`, GPLv3+, carrying five local
3//! patches marked `uncad local patch`; see `NOTICE.md` in this crate and
4//! docs/THIRD_PARTY_NOTICES.md).
5//! Generated by `build.rs` via `bindgen` against the public
6//! `dwg.h`/`dwg_api.h` headers plus this crate's own `uncad_*` C shims
7//! (see `shim/uncad_shim.h`).
8//!
9//! This crate is intentionally low-level and `unsafe`-heavy -- it exists to
10//! be wrapped by the `uncad` crate, not used directly.
11//!
12//! # Not thread-safe -- callers must serialize every call themselves
13//!
14//! The underlying LibreDWG C library has non-reentrant global state (e.g.
15//! the `loglevel` global read/written throughout `decode.c`/`bits.c`, and
16//! likely more that hasn't been individually catalogued). Calling into any
17//! function in this crate concurrently from multiple threads -- even two
18//! calls that never touch the same `Dwg_Data`/`Dwg_Object` -- has
19//! reproducibly caused `STATUS_HEAP_CORRUPTION` once both threads' work
20//! overlapped enough for the shared C-side state to race. **This crate does
21//! nothing to prevent that**; every FFI entry point here is exactly as
22//! unsynchronized as the C library it binds.
23//!
24//! The `uncad` crate's own public API (`uncad::parse()` and friends) is
25//! safe to call from multiple threads because it serializes every call
26//! through a single process-wide `Mutex` before reaching this crate --
27//! see `uncad`'s top-level doc comment / `docs/ARCHITECTURE.md`'s "Thread
28//! safety" section. Any other consumer of `libredwg-sys` directly must
29//! implement that same serialization itself (a single global lock around
30//! every call into this crate, held for the call's entire duration) or
31//! risk memory corruption under concurrent use.
32
33#![allow(non_upper_case_globals)]
34#![allow(non_camel_case_types)]
35#![allow(non_snake_case)]
36#![allow(dead_code)]
37// bindgen emits `mem::transmute(x)` for every bitfield accessor regardless
38// of whether the source and target types happen to coincide (they do for
39// every current `BITCODE_B`/`_BS`-backed bitfield in dwg.h) -- harmless,
40// and not something editing generated code (re-generated fresh on every
41// build) could fix. See docs/CAVEATS.md's "Clippy" note.
42#![allow(clippy::useless_transmute)]
43// Same rationale, for bindgen's generated `BindgenUninitializedField` helper
44// (`as_slice`/`as_mut_slice`/`as_ref`/`as_mut`) -- its `unsafe fn`s have no
45// `# Safety` doc section because bindgen doesn't emit one, not because this
46// crate's own unsafe code is undocumented (see `dynapi.rs` in `uncad` for
47// this project's own actual safety-doc convention).
48#![allow(clippy::missing_safety_doc)]
49// Same rationale again: bindgen's generated helper methods call other
50// unsafe functions (`slice::from_raw_parts`, `mem::transmute`) without
51// wrapping each one in its own `unsafe { }` block, relying on the whole
52// `unsafe fn` body being implicitly unsafe (2021 edition default) --
53// harmless and, again, not this crate's own code to restyle.
54#![allow(unsafe_op_in_unsafe_fn)]
55// bindgen 0.72 changed the bitfield accessors it emits to compute a byte
56// offset as `usize` and then cast it to `isize` for `.offset()`. clippy asks
57// for `.add()` instead, which is the right advice for hand-written code and
58// unactionable here: these bodies are regenerated from dwg.h on every build.
59// Same rationale as the three allows above.
60#![allow(clippy::ptr_offset_with_cast)]
61// bindgen 0.73 emits `(bits + 7) / 8` in the same bitfield accessors, which
62// clippy asks to write as `.div_ceil(8)`. Right for hand-written code, and
63// unactionable here for the same reason as the allows above: this file is
64// regenerated from dwg.h on every build.
65#![allow(clippy::manual_div_ceil)]
66
67include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
68
69// --- Hand-written struct mirrors ---------------------------------------
70//
71// bindgen cannot generate real field access for the types below, and this
72// crate needs it (see build.rs's blocklist_type calls for the failure mode).
73// Each one mirrors dwg.h's field order and types exactly; #[repr(C)] then
74// reproduces C's alignment and padding rules, and the compile-time size
75// assertions at the end of this section check the result against clang's own
76// sizeof() -- a safety net against a transcription mistake here.
77
78/// `_dwg_HATCH_ControlPoint` (dwg.h) -- a SPLINE-type boundary edge's
79/// control point.
80#[repr(C)]
81#[derive(Debug, Clone, Copy)]
82pub struct Dwg_HATCH_ControlPoint {
83 pub parent: *mut std::ffi::c_void,
84 pub point: BITCODE_2RD,
85 pub weight: BITCODE_BD,
86}
87
88/// `_dwg_HATCH_PathSeg` (dwg.h) -- one edge of a non-polyline HATCH boundary
89/// path. Not a real C union despite dwg.h's "could be a union" comment: every
90/// field is present regardless of `curve_type`, and only the ones relevant to
91/// that curve type are meaningfully populated.
92#[repr(C)]
93#[derive(Debug, Clone, Copy)]
94pub struct Dwg_HATCH_PathSeg {
95 pub parent: *mut std::ffi::c_void,
96 pub curve_type: BITCODE_RC,
97 /* LINE */
98 pub first_endpoint: BITCODE_2RD,
99 pub second_endpoint: BITCODE_2RD,
100 /* CIRCULAR ARC */
101 pub center: BITCODE_2RD,
102 pub radius: BITCODE_BD,
103 pub start_angle: BITCODE_BD,
104 pub end_angle: BITCODE_BD,
105 pub is_ccw: BITCODE_B,
106 /* ELLIPTICAL ARC */
107 pub endpoint: BITCODE_2RD,
108 pub minor_major_ratio: BITCODE_BD,
109 /* SPLINE */
110 pub degree: BITCODE_BL,
111 pub is_rational: BITCODE_B,
112 pub is_periodic: BITCODE_B,
113 pub num_knots: BITCODE_BL,
114 pub num_control_points: BITCODE_BL,
115 pub knots: *mut BITCODE_BD,
116 pub control_points: *mut Dwg_HATCH_ControlPoint,
117 pub num_fitpts: BITCODE_BL,
118 pub fitpts: *mut BITCODE_2RD,
119 pub start_tangent: BITCODE_2RD,
120 pub end_tangent: BITCODE_2RD,
121}
122
123/// `_dwg_HATCH_Path` (dwg.h) -- one HATCH boundary path, either a
124/// polyline (`polyline_paths`, when `flag & 0x02`) or a list of curved/
125/// straight edges (`segs`).
126#[repr(C)]
127#[derive(Debug, Clone, Copy)]
128pub struct Dwg_HATCH_Path {
129 pub parent: *mut std::ffi::c_void,
130 pub flag: BITCODE_BL,
131 pub num_segs_or_paths: BITCODE_BL,
132 pub segs: *mut Dwg_HATCH_PathSeg,
133 pub bulges_present: BITCODE_B,
134 pub closed: BITCODE_B,
135 pub polyline_paths: *mut Dwg_HATCH_PolylinePath,
136 pub num_boundary_handles: BITCODE_BL,
137 pub boundary_handles: *mut *mut Dwg_Object_Ref,
138}
139
140// _dwg_HATCH_PolylinePath is still bindgen-generated and refers to the raw tag
141// name in its `parent` field, so the alias has to exist even though nothing
142// else here uses it.
143pub type _dwg_HATCH_Path = Dwg_HATCH_Path;
144
145/// `_dwg_HATCH_DefLine` (dwg.h) -- one pattern-fill "definition line": a family
146/// of parallel lines (`angle`/`pt0`/`offset`) plus an optional dash pattern
147/// (`dashes`: positive = dash length, negative = gap, empty = continuous). One
148/// of `Dwg_Entity_HATCH.deflines`.
149///
150/// `pt0`/`offset` are declared `BITCODE_2BD` in dwg.h but typed `BITCODE_2RD`
151/// here: both are two `double`s with no padding, and `BITCODE_2RD` is already
152/// bound elsewhere in this crate, so reusing it avoids pulling in a type
153/// bindgen would otherwise never generate.
154#[repr(C)]
155#[derive(Debug, Clone, Copy)]
156pub struct Dwg_HATCH_DefLine {
157 pub parent: *mut std::ffi::c_void,
158 pub angle: BITCODE_BD,
159 pub pt0: BITCODE_2RD,
160 pub offset: BITCODE_2RD,
161 pub num_dashes: BITCODE_BS,
162 pub dashes: *mut BITCODE_BD,
163}
164pub type _dwg_HATCH_DefLine = Dwg_HATCH_DefLine;
165
166/// `_dwg_HATCH_Color` (dwg.h) -- one gradient-fill color stop: `shift_value`
167/// (0.0-1.0, its position along the gradient) plus a plain `Dwg_Color`. One of
168/// `Dwg_Entity_HATCH.colors`.
169#[repr(C)]
170#[derive(Debug, Clone, Copy)]
171pub struct Dwg_HATCH_Color {
172 pub parent: *mut std::ffi::c_void,
173 pub shift_value: BITCODE_BD,
174 pub color: Dwg_Color,
175}
176pub type _dwg_HATCH_Color = Dwg_HATCH_Color;
177
178/// `_dwg_MLINE_vertex` (dwg.h). Its `vertex`/`vertex_direction`/
179/// `miter_direction` fields are declared `BITCODE_3BD`, which bindgen never
180/// generates on its own; `dwg_point_3d` stands in, being the same three
181/// `double`s with no padding. `lines` (the per-vertex parallel-line array) is
182/// left as an untyped `*mut c_void` because nothing dereferences it, which
183/// saves hand-writing `Dwg_MLINE_line` as well.
184#[repr(C)]
185#[derive(Debug, Clone, Copy)]
186pub struct Dwg_MLINE_vertex {
187 pub parent: *mut std::ffi::c_void,
188 pub vertex: dwg_point_3d,
189 pub vertex_direction: dwg_point_3d,
190 pub miter_direction: dwg_point_3d,
191 pub num_lines: BITCODE_RC,
192 pub lines: *mut std::ffi::c_void,
193}
194
195/// `_dwg_MLINESTYLE_line` (dwg.h) -- one parallel-line definition in an
196/// MLINESTYLE object: `offset` (distance from the MLINE centerline, combined
197/// with each vertex's `miter_direction` to get that line's actual point) plus
198/// `color`/`lt_index`/`lt_ltype`, none of which this workspace renders.
199/// `lt_ltype` is typed properly rather than left opaque, `Dwg_Object_Ref`
200/// already being a bound type here.
201#[repr(C)]
202#[derive(Debug, Clone, Copy)]
203pub struct Dwg_MLINESTYLE_line {
204 pub parent: *mut std::ffi::c_void,
205 pub offset: BITCODE_BD,
206 pub color: Dwg_Color,
207 pub lt_index: BITCODE_BSd,
208 pub lt_ltype: *mut Dwg_Object_Ref,
209}
210pub type _dwg_MLINESTYLE_line = Dwg_MLINESTYLE_line;
211
212#[allow(clippy::unnecessary_operation, clippy::identity_op)]
213const _: () = {
214 ["Size of Dwg_HATCH_ControlPoint"][std::mem::size_of::<Dwg_HATCH_ControlPoint>() - 32];
215 ["Size of Dwg_HATCH_PathSeg"][std::mem::size_of::<Dwg_HATCH_PathSeg>() - 200];
216 ["Size of Dwg_HATCH_Path"][std::mem::size_of::<Dwg_HATCH_Path>() - 56];
217 ["Size of Dwg_HATCH_DefLine"][std::mem::size_of::<Dwg_HATCH_DefLine>() - 64];
218 ["Size of Dwg_HATCH_Color"][std::mem::size_of::<Dwg_HATCH_Color>() - 64];
219 ["Size of Dwg_MLINE_vertex"][std::mem::size_of::<Dwg_MLINE_vertex>() - 96];
220 ["Size of Dwg_MLINESTYLE_line"][std::mem::size_of::<Dwg_MLINESTYLE_line>() - 80];
221};