libredwg_sys/lib.rs
1//! Raw FFI bindings to the LibreDWG C sources (vendored, unmodified, from
2//! the real upstream project at `lib/libredwg`, GPLv3+; see
3//! docs/THIRD_PARTY_NOTICES.md).
4//! Generated by `build.rs` via `bindgen` against the public
5//! `dwg.h`/`dwg_api.h` headers plus this crate's own `uncad_write_dxf_file`
6//! shim (see `shim/uncad_shim.h`).
7//!
8//! This crate is intentionally low-level and `unsafe`-heavy -- it exists to
9//! be wrapped by the `uncad` crate, not used directly.
10//!
11//! # Not thread-safe -- callers must serialize every call themselves
12//!
13//! The underlying LibreDWG C library has non-reentrant global state (e.g.
14//! the `loglevel` global read/written throughout `decode.c`/`bits.c`, and
15//! likely more that hasn't been individually catalogued). Calling into any
16//! function in this crate concurrently from multiple threads -- even two
17//! calls that never touch the same `Dwg_Data`/`Dwg_Object` -- has
18//! reproducibly caused `STATUS_HEAP_CORRUPTION` once both threads' work
19//! overlapped enough for the shared C-side state to race. **This crate does
20//! nothing to prevent that**; every FFI entry point here is exactly as
21//! unsynchronized as the C library it binds.
22//!
23//! The `uncad` crate's own public API (`uncad::parse()` and friends) is
24//! safe to call from multiple threads because it serializes every call
25//! through a single process-wide `Mutex` before reaching this crate --
26//! see `uncad`'s top-level doc comment / `docs/ARCHITECTURE.md`'s "Thread
27//! safety" section. Any other consumer of `libredwg-sys` directly must
28//! implement that same serialization itself (a single global lock around
29//! every call into this crate, held for the call's entire duration) or
30//! risk memory corruption under concurrent use.
31
32#![allow(non_upper_case_globals)]
33#![allow(non_camel_case_types)]
34#![allow(non_snake_case)]
35#![allow(dead_code)]
36// bindgen emits `mem::transmute(x)` for every bitfield accessor regardless
37// of whether the source and target types happen to coincide (they do for
38// every current `BITCODE_B`/`_BS`-backed bitfield in dwg.h) -- harmless,
39// and not something editing generated code (re-generated fresh on every
40// build) could fix. See docs/CAVEATS.md's "cargo clippy 현재 상태" note.
41#![allow(clippy::useless_transmute)]
42// Same rationale, for bindgen's generated `BindgenUninitializedField` helper
43// (`as_slice`/`as_mut_slice`/`as_ref`/`as_mut`) -- its `unsafe fn`s have no
44// `# Safety` doc section because bindgen doesn't emit one, not because this
45// crate's own unsafe code is undocumented (see `dynapi.rs` in `uncad` for
46// this project's own actual safety-doc convention).
47#![allow(clippy::missing_safety_doc)]
48// Same rationale again: bindgen's generated helper methods call other
49// unsafe functions (`slice::from_raw_parts`, `mem::transmute`) without
50// wrapping each one in its own `unsafe { }` block, relying on the whole
51// `unsafe fn` body being implicitly unsafe (2021 edition default) --
52// harmless and, again, not this crate's own code to restyle.
53#![allow(unsafe_op_in_unsafe_fn)]
54
55include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
56
57// --- Hand-defined HATCH sub-structs -----------------------------------
58//
59// bindgen can't generate real field access for these two (same struct-
60// codegen limitation as Dwg_Object -- see build.rs's blocklist_type calls
61// for the full explanation), but this project needs real field access
62// into them (HATCH boundary-path geometry isn't reachable through dynapi
63// at all -- dynapi only exposes top-level entity fields by name, not
64// nested struct internals). Hand-defined here to match dwg.h's field
65// order and types exactly; #[repr(C)] then reproduces C's own alignment/
66// padding rules automatically; the layout_test() functions below assert
67// the resulting sizes against clang's own authoritative sizeof() (56/200/
68// 32 bytes -- the same numbers bindgen's own layout_tests() asserted
69// against before these types were blocklisted) as a safety net against a
70// transcription mistake in this hand-written mirror.
71
72/// `_dwg_HATCH_ControlPoint` (dwg.h) -- a SPLINE-type boundary edge's
73/// control point.
74#[repr(C)]
75#[derive(Debug, Clone, Copy)]
76pub struct Dwg_HATCH_ControlPoint {
77 pub parent: *mut std::ffi::c_void,
78 pub point: BITCODE_2RD,
79 pub weight: BITCODE_BD,
80}
81
82/// `_dwg_HATCH_PathSeg` (dwg.h) -- one edge of a non-polyline HATCH
83/// boundary path. Not a real C union (despite the "could be a union"
84/// comment in dwg.h) -- every field is present regardless of
85/// `curve_type`; only the fields relevant to that specific curve type are
86/// meaningfully populated.
87#[repr(C)]
88#[derive(Debug, Clone, Copy)]
89pub struct Dwg_HATCH_PathSeg {
90 pub parent: *mut std::ffi::c_void,
91 pub curve_type: BITCODE_RC,
92 /* LINE */
93 pub first_endpoint: BITCODE_2RD,
94 pub second_endpoint: BITCODE_2RD,
95 /* CIRCULAR ARC */
96 pub center: BITCODE_2RD,
97 pub radius: BITCODE_BD,
98 pub start_angle: BITCODE_BD,
99 pub end_angle: BITCODE_BD,
100 pub is_ccw: BITCODE_B,
101 /* ELLIPTICAL ARC */
102 pub endpoint: BITCODE_2RD,
103 pub minor_major_ratio: BITCODE_BD,
104 /* SPLINE */
105 pub degree: BITCODE_BL,
106 pub is_rational: BITCODE_B,
107 pub is_periodic: BITCODE_B,
108 pub num_knots: BITCODE_BL,
109 pub num_control_points: BITCODE_BL,
110 pub knots: *mut BITCODE_BD,
111 pub control_points: *mut Dwg_HATCH_ControlPoint,
112 pub num_fitpts: BITCODE_BL,
113 pub fitpts: *mut BITCODE_2RD,
114 pub start_tangent: BITCODE_2RD,
115 pub end_tangent: BITCODE_2RD,
116}
117
118/// `_dwg_HATCH_Path` (dwg.h) -- one HATCH boundary path, either a
119/// polyline (`polyline_paths`, when `flag & 0x02`) or a list of curved/
120/// straight edges (`segs`).
121#[repr(C)]
122#[derive(Debug, Clone, Copy)]
123pub struct Dwg_HATCH_Path {
124 pub parent: *mut std::ffi::c_void,
125 pub flag: BITCODE_BL,
126 pub num_segs_or_paths: BITCODE_BL,
127 pub segs: *mut Dwg_HATCH_PathSeg,
128 pub bulges_present: BITCODE_B,
129 pub closed: BITCODE_B,
130 pub polyline_paths: *mut Dwg_HATCH_PolylinePath,
131 pub num_boundary_handles: BITCODE_BL,
132 pub boundary_handles: *mut *mut Dwg_Object_Ref,
133}
134
135// _dwg_HATCH_PolylinePath (still bindgen-generated -- not blocklisted)
136// references the raw tag name `_dwg_HATCH_Path` directly in its `parent`
137// field, so this alias needs to exist even though nothing in this crate
138// otherwise uses the tag name (only the `Dwg_HATCH_Path` typedef above).
139pub type _dwg_HATCH_Path = Dwg_HATCH_Path;
140
141/// `_dwg_HATCH_DefLine` (dwg.h) -- one pattern-fill "definition line": a
142/// family of parallel lines (`angle`/`pt0`/`offset`, in the pattern's own
143/// unscaled/unrotated definition space) plus an optional dash pattern
144/// (`dashes`, positive = dash length, negative = gap length; empty means a
145/// continuous line) -- one of `Dwg_Entity_HATCH.deflines`. Unlike
146/// `Dwg_HATCH_Path`/`PathSeg`/`ControlPoint` above, this one *is* reachable
147/// through dynapi (`num_deflines`/`deflines` are plain top-level
148/// `Dwg_Entity_HATCH` fields, not nested inside a Path/PathSeg element) --
149/// but it still has to be hand-defined and blocklisted the same way,
150/// because allowlisting it directly forces bindgen to also generate a real
151/// (non-opaque) `_dwg_entity_HATCH` for its `parent` field to point at
152/// (nothing else in this crate ever allowlists `_dwg_entity_HATCH`; HATCH's
153/// own fields are all read through dynapi's untyped `void*`), and
154/// `_dwg_entity_HATCH` itself then hits the identical struct-codegen
155/// failure. `parent` is left as an untyped `*mut c_void` here specifically
156/// to avoid that cascade, matching the other three HATCH sub-structs' own
157/// `parent` fields. `pt0`/`offset` are declared `BITCODE_2BD` in dwg.h, but
158/// typed `BITCODE_2RD` here instead -- same interchangeable-once-decoded
159/// reasoning as `Point2D`'s own doc comment (both are just 2 `double`s with
160/// no padding); `BITCODE_2RD` is already a bound type elsewhere in this
161/// crate (`Dwg_HATCH_PathSeg`), while nothing else pulls in the separate
162/// `BITCODE_2BD` alias, so reusing it avoids introducing a type bindgen
163/// would otherwise never generate.
164#[repr(C)]
165#[derive(Debug, Clone, Copy)]
166pub struct Dwg_HATCH_DefLine {
167 pub parent: *mut std::ffi::c_void,
168 pub angle: BITCODE_BD,
169 pub pt0: BITCODE_2RD,
170 pub offset: BITCODE_2RD,
171 pub num_dashes: BITCODE_BS,
172 pub dashes: *mut BITCODE_BD,
173}
174pub type _dwg_HATCH_DefLine = Dwg_HATCH_DefLine;
175
176/// `_dwg_HATCH_Color` (dwg.h) -- one gradient-fill color stop: `shift_value`
177/// (0.0-1.0, this stop's position along the gradient) plus `color` (a plain
178/// `Dwg_Color`, already a normally-bound type elsewhere in this crate --
179/// e.g. entity/layer color -- so no further hand-writing needed for it).
180/// One of `Dwg_Entity_HATCH.colors` (`num_colors`/`colors`). Same
181/// `parent: struct _dwg_entity_HATCH *` cascade as `Dwg_HATCH_DefLine`
182/// above (allowlisting it directly forces bindgen to also materialize a
183/// real, cascade-failing `_dwg_entity_HATCH`), same fix: blocklisted and
184/// hand-defined with `parent` left as an untyped `*mut c_void`. Verified
185/// against clang's own authoritative `sizeof()` (64 bytes: parent@0,
186/// shift_value@8, color@16) via the same allowlist-then-read-the-failing-
187/// layout_tests()-assert technique used for the other hand-written HATCH
188/// sub-structs.
189#[repr(C)]
190#[derive(Debug, Clone, Copy)]
191pub struct Dwg_HATCH_Color {
192 pub parent: *mut std::ffi::c_void,
193 pub shift_value: BITCODE_BD,
194 pub color: Dwg_Color,
195}
196pub type _dwg_HATCH_Color = Dwg_HATCH_Color;
197
198/// `_dwg_MLINE_vertex` (dwg.h) -- same bindgen struct-codegen failure as
199/// the HATCH types above, hand-defined the same way. Its `vertex`/
200/// `vertex_direction`/`miter_direction` fields are declared `BITCODE_3BD`
201/// in dwg.h, which bindgen never generates a binding for on its own (only
202/// pulled in transitively by whatever references it, and nothing
203/// currently allowlisted does) -- `dwg_point_3d` is used instead, since
204/// `BITCODE_3BD`/`Dwg_Bitcode_3BD` is just 3 `double`s with no padding,
205/// identically laid out. `lines` (the per-vertex parallel-line array,
206/// `Dwg_MLINE_line*`) is declared as an opaque `*mut c_void` here rather
207/// than a real pointer type -- nothing in this crate reads through it
208/// (`uncad`'s MLINE rendering only uses `vertex`, the centerline point;
209/// see docs/CAVEATS.md), and leaving it untyped avoids also needing to
210/// bind/hand-write `Dwg_MLINE_line` just for a field no caller
211/// dereferences.
212#[repr(C)]
213#[derive(Debug, Clone, Copy)]
214pub struct Dwg_MLINE_vertex {
215 pub parent: *mut std::ffi::c_void,
216 pub vertex: dwg_point_3d,
217 pub vertex_direction: dwg_point_3d,
218 pub miter_direction: dwg_point_3d,
219 pub num_lines: BITCODE_RC,
220 pub lines: *mut std::ffi::c_void,
221}
222
223/// `_dwg_MLINESTYLE_line` (dwg.h) -- one parallel-line definition in an
224/// MLINESTYLE OBJECT: `offset` (distance from the MLINE centerline,
225/// combined with each MLINE vertex's own `miter_direction` to get that
226/// line's actual point -- see `uncad`'s `convert::convert_mline` doc
227/// comment) plus `color`/`lt_index`/`lt_ltype` (this project only reads
228/// `offset`; the rest aren't used for rendering). Same
229/// `parent: struct _dwg_object_MLINESTYLE *` cascade as the HATCH
230/// sub-structs above (confirmed: allowlisting it alone produces a
231/// `1usize - 112usize` layout_tests() assert on `_dwg_object_MLINESTYLE`).
232/// Blocklisted and hand-defined instead, same recipe -- verified against
233/// clang's real `sizeof()` (80 bytes: parent@0, offset@8, color@16,
234/// lt_index@64, lt_ltype@72) the same way. `lt_ltype` (`BITCODE_H`, since
235/// 2018) is a real `*mut Dwg_Object_Ref` here rather than an opaque
236/// `c_void` pointer -- `Dwg_Object_Ref` is already a plain bound type
237/// elsewhere in this crate, so there's no extra hand-writing needed to type
238/// it correctly, unlike `Dwg_MLINE_vertex.lines` above.
239#[repr(C)]
240#[derive(Debug, Clone, Copy)]
241pub struct Dwg_MLINESTYLE_line {
242 pub parent: *mut std::ffi::c_void,
243 pub offset: BITCODE_BD,
244 pub color: Dwg_Color,
245 pub lt_index: BITCODE_BSd,
246 pub lt_ltype: *mut Dwg_Object_Ref,
247}
248pub type _dwg_MLINESTYLE_line = Dwg_MLINESTYLE_line;
249
250#[allow(clippy::unnecessary_operation, clippy::identity_op)]
251const _: () = {
252 ["Size of Dwg_HATCH_ControlPoint"][std::mem::size_of::<Dwg_HATCH_ControlPoint>() - 32];
253 ["Size of Dwg_HATCH_PathSeg"][std::mem::size_of::<Dwg_HATCH_PathSeg>() - 200];
254 ["Size of Dwg_HATCH_Path"][std::mem::size_of::<Dwg_HATCH_Path>() - 56];
255 ["Size of Dwg_HATCH_DefLine"][std::mem::size_of::<Dwg_HATCH_DefLine>() - 64];
256 ["Size of Dwg_HATCH_Color"][std::mem::size_of::<Dwg_HATCH_Color>() - 64];
257 ["Size of Dwg_MLINE_vertex"][std::mem::size_of::<Dwg_MLINE_vertex>() - 96];
258 ["Size of Dwg_MLINESTYLE_line"][std::mem::size_of::<Dwg_MLINESTYLE_line>() - 80];
259};