1use std::collections::HashMap;
8
9use xfa_dom_resolver::data_dom::{DataDom, DataNodeId};
10use xfa_dom_resolver::som::{
11 parse_som, resolve_data_path, SomExpression, SomIndex, SomRoot, SomSelector,
12};
13use xfa_layout_engine::form::{FormNodeId, FormNodeType, FormTree, GroupKind};
14
15use super::RuntimeMetadata;
16
17pub const MAX_MUTATIONS_PER_DOC: usize = 4096;
19pub const MAX_INSTANCES_PER_SUBFORM: u32 = 256;
21pub const MAX_ITEMS_PER_LISTBOX: u32 = 4096;
23pub const MAX_RESOLVE_CALLS_PER_SCRIPT: u32 = 1024;
25pub const MAX_RESOLVE_RESULTS: usize = 256;
27pub const MAX_SOM_DEPTH: usize = 16;
29
30#[derive(Debug, Clone, PartialEq, Eq)]
32pub struct MutationLogEntry {
33 pub node_id: FormNodeId,
35 pub script_idx: usize,
37 pub before: String,
39 pub after: String,
41}
42
43#[derive(Debug)]
45pub struct HostBindings {
46 form: *mut FormTree,
47 root_id: FormNodeId,
48 current_id: Option<FormNodeId>,
49 current_activity: Option<String>,
50 current_script_idx: usize,
51 next_script_idx: usize,
52 generation: u64,
53 mutation_log: Vec<MutationLogEntry>,
54 mutation_count_this_doc: usize,
55 resolve_count_this_script: u32,
56 metadata: RuntimeMetadata,
57 static_page_count: u32,
58 zero_instance_runs: HashMap<(FormNodeId, String), u64>,
59 data_dom: Option<*const DataDom>,
63}
64
65impl Default for HostBindings {
66 fn default() -> Self {
67 Self {
68 form: std::ptr::null_mut(),
69 root_id: FormNodeId(0),
70 current_id: None,
71 current_activity: None,
72 current_script_idx: 0,
73 next_script_idx: 0,
74 generation: 0,
75 mutation_log: Vec::new(),
76 mutation_count_this_doc: 0,
77 resolve_count_this_script: 0,
78 metadata: RuntimeMetadata::default(),
79 static_page_count: 0,
80 zero_instance_runs: HashMap::new(),
81 data_dom: None,
82 }
83 }
84}
85
86impl HostBindings {
87 pub fn new() -> Self {
89 Self::default()
90 }
91
92 pub fn set_form_handle(&mut self, form: *mut FormTree, root_id: FormNodeId) {
94 self.form = form;
95 self.root_id = root_id;
96 if form.is_null() {
97 self.current_id = None;
98 self.current_activity = None;
99 self.current_script_idx = 0;
100 self.zero_instance_runs.clear();
101 }
102 }
103
104 pub fn reset_per_document(&mut self) {
113 self.form = std::ptr::null_mut();
114 self.root_id = FormNodeId(0);
115 self.current_id = None;
116 self.current_activity = None;
117 self.current_script_idx = 0;
118 self.next_script_idx = 0;
119 self.generation = self.generation.wrapping_add(1);
120 self.mutation_log.clear();
121 self.mutation_count_this_doc = 0;
122 self.resolve_count_this_script = 0;
123 self.metadata = RuntimeMetadata::default();
124 self.static_page_count = 0;
125 self.zero_instance_runs.clear();
126 }
128
129 pub fn set_data_handle(&mut self, dom: *const DataDom) {
133 self.data_dom = Some(dom);
134 }
135
136 pub fn reset_per_script(&mut self, current_id: FormNodeId, activity: Option<&str>) {
138 self.current_id = Some(current_id);
139 self.current_activity = activity.map(str::to_string);
140 self.current_script_idx = self.next_script_idx;
141 self.next_script_idx = self.next_script_idx.saturating_add(1);
142 self.resolve_count_this_script = 0;
143 }
144
145 pub fn set_static_page_count(&mut self, page_count: u32) {
147 self.static_page_count = page_count;
148 }
149
150 pub fn generation(&self) -> u64 {
153 self.generation
154 }
155
156 pub fn current_node(&self) -> Option<FormNodeId> {
158 self.current_id
159 }
160
161 pub fn root_node(&mut self, generation: u64) -> Option<FormNodeId> {
163 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
164 if generation != self.generation {
165 return None;
166 }
167 let Some(form) = self.form_ref() else {
168 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
169 return None;
170 };
171 (self.root_id.0 < form.nodes.len()).then_some(self.root_id)
172 }
173
174 pub fn subform_scope_chain(&mut self, node_id: FormNodeId, generation: u64) -> Vec<String> {
180 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
181 if !self.handle_is_live(node_id, generation) {
182 return vec![];
183 }
184 let Some(form) = self.form_ref() else {
185 return vec![];
186 };
187 let root = self.root_id;
188 let mut names: Vec<String> = vec![];
191 let mut stack: Vec<(FormNodeId, usize, bool)> = vec![(root, 0, false)];
192 while let Some(&(current, child_idx, _pushed)) = stack.last() {
193 if current == node_id {
194 return names;
195 }
196 let children_len = form.get(current).children.len();
197 if child_idx >= children_len {
198 let (_, _, pushed) = stack.pop().unwrap();
199 if pushed {
200 names.pop();
201 }
202 continue;
203 }
204 let child_id = form.get(current).children[child_idx];
205 stack.last_mut().unwrap().1 += 1;
206 let child = form.get(child_id);
207 let is_scope = matches!(
208 child.node_type,
209 FormNodeType::Subform | FormNodeType::Area | FormNodeType::ExclGroup
210 );
211 let pushed = is_scope && !child.name.is_empty();
212 if pushed {
213 names.push(child.name.clone());
214 }
215 stack.push((child_id, 0, pushed));
216 }
217 vec![]
218 }
219
220 pub fn take_metadata(&mut self) -> RuntimeMetadata {
222 std::mem::take(&mut self.metadata)
223 }
224
225 pub fn mutation_log(&self) -> &[MutationLogEntry] {
227 &self.mutation_log
228 }
229
230 pub fn get_raw_value(&mut self, node_id: FormNodeId, generation: u64) -> Option<String> {
233 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
234 if !self.handle_is_live(node_id, generation) {
235 return None;
236 }
237 let Some(form) = self.form_ref() else {
238 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
239 return None;
240 };
241 match &form.get(node_id).node_type {
242 FormNodeType::Field { value } => Some(value.clone()),
243 _ => None,
244 }
245 }
246
247 pub fn node_name(&self, node_id: FormNodeId, generation: u64) -> Option<String> {
250 if !self.handle_is_live(node_id, generation) {
251 return None;
252 }
253 let form = self.form_ref()?;
254 Some(form.get(node_id).name.clone())
255 }
256
257 pub fn get_occur_property(
259 &mut self,
260 node_id: FormNodeId,
261 generation: u64,
262 property: &str,
263 ) -> Option<i32> {
264 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
265 if !self.handle_is_live(node_id, generation) {
266 return None;
267 }
268 let Some(form) = self.form_ref() else {
269 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
270 return None;
271 };
272 let occur = &form.get(node_id).occur;
273 match property {
274 "min" => Some(clamp_occur_to_i32(occur.min)),
275 "max" => Some(occur.max.map(clamp_occur_to_i32).unwrap_or(-1)),
276 "initial" => Some(clamp_occur_to_i32(occur.initial)),
277 _ => {
278 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
279 None
280 }
281 }
282 }
283
284 pub fn set_occur_property(
286 &mut self,
287 node_id: FormNodeId,
288 generation: u64,
289 property: &str,
290 value: &str,
291 ) -> bool {
292 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
293 if !self.write_activity_allowed()
294 || !self.handle_is_live(node_id, generation)
295 || self.mutation_count_this_doc >= MAX_MUTATIONS_PER_DOC
296 {
297 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
298 return false;
299 }
300
301 enum OccurValue {
302 Nonnegative(u32),
303 Max(Option<u32>),
304 }
305
306 let parsed = match property {
307 "min" | "initial" => parse_nonnegative_occur_value(value).map(OccurValue::Nonnegative),
308 "max" => parse_max_occur_value(value).map(OccurValue::Max),
309 _ => None,
310 };
311 let Some(parsed) = parsed else {
312 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
313 return false;
314 };
315
316 let Some(form) = self.form_mut() else {
317 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
318 return false;
319 };
320 let Some(node) = form.nodes.get_mut(node_id.0) else {
321 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
322 return false;
323 };
324 match (property, parsed) {
325 ("min", OccurValue::Nonnegative(n)) => node.occur.min = n,
326 ("initial", OccurValue::Nonnegative(n)) => node.occur.initial = n,
327 ("max", OccurValue::Max(n)) => node.occur.max = n,
328 _ => {
329 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
330 return false;
331 }
332 }
333 self.mutation_count_this_doc = self.mutation_count_this_doc.saturating_add(1);
334 true
335 }
336
337 pub fn set_raw_value(&mut self, node_id: FormNodeId, value: String, generation: u64) -> bool {
339 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
340 if !self.write_activity_allowed()
341 || !self.handle_is_live(node_id, generation)
342 || self.mutation_count_this_doc >= MAX_MUTATIONS_PER_DOC
343 {
344 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
345 return false;
346 }
347
348 let Some((before, after)) = self.write_field_value(node_id, value) else {
349 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
350 return false;
351 };
352
353 self.mutation_log.push(MutationLogEntry {
354 node_id,
355 script_idx: self.current_script_idx,
356 before,
357 after,
358 });
359 self.metadata.mutations = self.metadata.mutations.saturating_add(1);
360 self.mutation_count_this_doc = self.mutation_count_this_doc.saturating_add(1);
361 true
362 }
363
364 pub fn resolve_node(&mut self, path: &str) -> Option<FormNodeId> {
366 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
367 let nodes = match self.resolve_path(path) {
368 ResolveOutcome::Ok(nodes) => nodes,
369 ResolveOutcome::NoMatch => {
370 self.metadata.resolve_failures = self.metadata.resolve_failures.saturating_add(1);
371 return None;
372 }
373 ResolveOutcome::BindingError => {
374 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
375 return None;
376 }
377 };
378
379 let Some(form) = self.form_ref() else {
380 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
381 return None;
382 };
383 let found = nodes
384 .into_iter()
385 .find(|node_id| matches!(form.get(*node_id).node_type, FormNodeType::Field { .. }));
386 if found.is_none() {
387 self.metadata.resolve_failures = self.metadata.resolve_failures.saturating_add(1);
388 }
389 found
390 }
391
392 pub fn resolve_nodes(&mut self, path: &str) -> Vec<FormNodeId> {
395 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
396 let nodes = match self.resolve_path(path) {
397 ResolveOutcome::Ok(nodes) => nodes,
398 ResolveOutcome::NoMatch => return Vec::new(),
399 ResolveOutcome::BindingError => {
400 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
401 self.metadata.resolve_failures = self.metadata.resolve_failures.saturating_add(1);
402 return Vec::new();
403 }
404 };
405
406 let Some(form) = self.form_ref() else {
407 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
408 return Vec::new();
409 };
410 nodes
411 .into_iter()
412 .filter(|node_id| matches!(form.get(*node_id).node_type, FormNodeType::Field { .. }))
413 .take(MAX_RESOLVE_RESULTS)
414 .collect()
415 }
416
417 pub fn resolve_implicit(&mut self, current_id: FormNodeId, name: &str) -> Option<FormNodeId> {
424 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
425 match self.resolve_implicit_inner(current_id, name) {
426 ResolveOutcome::Ok(nodes) => nodes.into_iter().next(),
427 ResolveOutcome::NoMatch => {
428 self.metadata.resolve_failures = self.metadata.resolve_failures.saturating_add(1);
429 None
430 }
431 ResolveOutcome::BindingError => {
432 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
433 None
434 }
435 }
436 }
437
438 pub fn resolve_implicit_candidates(
444 &mut self,
445 current_id: FormNodeId,
446 name: &str,
447 ) -> Vec<FormNodeId> {
448 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
449 match self.resolve_implicit_inner(current_id, name) {
450 ResolveOutcome::Ok(nodes) => nodes,
451 ResolveOutcome::NoMatch => {
452 self.metadata.resolve_failures = self.metadata.resolve_failures.saturating_add(1);
453 Vec::new()
454 }
455 ResolveOutcome::BindingError => {
456 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
457 Vec::new()
458 }
459 }
460 }
461
462 pub fn resolve_child(&mut self, parent_id: FormNodeId, name: &str) -> Option<FormNodeId> {
464 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
465 match self.resolve_child_inner(parent_id, name) {
466 ResolveOutcome::Ok(nodes) => nodes.into_iter().next(),
467 ResolveOutcome::NoMatch => {
468 self.metadata.resolve_failures = self.metadata.resolve_failures.saturating_add(1);
469 None
470 }
471 ResolveOutcome::BindingError => {
472 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
473 None
474 }
475 }
476 }
477
478 pub fn resolve_child_candidates(
485 &mut self,
486 parent_ids: &[FormNodeId],
487 name: &str,
488 ) -> Vec<FormNodeId> {
489 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
490 match self.resolve_child_candidates_inner(parent_ids, name) {
491 ResolveOutcome::Ok(nodes) => nodes,
492 ResolveOutcome::NoMatch => {
493 self.metadata.resolve_failures = self.metadata.resolve_failures.saturating_add(1);
494 Vec::new()
495 }
496 ResolveOutcome::BindingError => {
497 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
498 Vec::new()
499 }
500 }
501 }
502
503 pub fn resolve_scoped_candidates(
509 &mut self,
510 scope_ids: &[FormNodeId],
511 name: &str,
512 ) -> Vec<FormNodeId> {
513 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
514 match self.resolve_scoped_candidates_inner(scope_ids, name) {
515 ResolveOutcome::Ok(nodes) => nodes,
516 ResolveOutcome::NoMatch => {
517 self.metadata.resolve_failures = self.metadata.resolve_failures.saturating_add(1);
518 Vec::new()
519 }
520 ResolveOutcome::BindingError => {
521 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
522 Vec::new()
523 }
524 }
525 }
526
527 pub fn instance_count(&mut self, parent_id: FormNodeId) -> u32 {
529 self.instance_count_inner(parent_id, None)
530 }
531
532 pub fn instance_count_for_handle(&mut self, parent_id: FormNodeId, generation: u64) -> u32 {
534 self.instance_count_inner(parent_id, Some(generation))
535 }
536
537 pub fn instance_index(&mut self, node_id: FormNodeId) -> u32 {
539 self.instance_index_inner(node_id, None)
540 }
541
542 pub fn instance_index_for_handle(&mut self, node_id: FormNodeId, generation: u64) -> u32 {
544 self.instance_index_inner(node_id, Some(generation))
545 }
546
547 pub fn has_zero_instance_run(
552 &mut self,
553 parent_id: FormNodeId,
554 generation: u64,
555 name: &str,
556 ) -> bool {
557 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
558 let name = name.trim();
559 if name.is_empty() || !self.consume_resolve_call() {
560 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
561 return false;
562 }
563 let Some(form) = self.form_ref() else {
564 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
565 return false;
566 };
567 if generation != self.generation || parent_id.0 >= form.nodes.len() {
568 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
569 return false;
570 }
571 self.zero_instance_runs
572 .contains_key(&(parent_id, name.to_string()))
573 }
574
575 #[allow(clippy::result_unit_err)]
578 pub fn instance_set(&mut self, parent_id: FormNodeId, n: u32) -> Result<u32, ()> {
579 self.instance_set_inner(parent_id, None, n)
580 }
581
582 #[allow(clippy::result_unit_err)]
584 pub fn instance_set_for_handle(
585 &mut self,
586 parent_id: FormNodeId,
587 generation: u64,
588 n: u32,
589 ) -> Result<u32, ()> {
590 self.instance_set_inner(parent_id, Some(generation), n)
591 }
592
593 #[allow(clippy::result_unit_err)]
595 pub fn instance_add(&mut self, parent_id: FormNodeId) -> Result<FormNodeId, ()> {
596 self.instance_add_inner(parent_id, None)
597 }
598
599 #[allow(clippy::result_unit_err)]
601 pub fn instance_add_for_handle(
602 &mut self,
603 parent_id: FormNodeId,
604 generation: u64,
605 ) -> Result<FormNodeId, ()> {
606 self.instance_add_inner(parent_id, Some(generation))
607 }
608
609 #[allow(clippy::result_unit_err)]
611 pub fn instance_remove(&mut self, parent_id: FormNodeId, index: u32) -> Result<(), ()> {
612 self.instance_remove_inner(parent_id, None, index)
613 }
614
615 #[allow(clippy::result_unit_err)]
617 pub fn instance_remove_for_handle(
618 &mut self,
619 parent_id: FormNodeId,
620 generation: u64,
621 index: u32,
622 ) -> Result<(), ()> {
623 self.instance_remove_inner(parent_id, Some(generation), index)
624 }
625
626 #[allow(clippy::result_unit_err)]
628 pub fn list_clear(&mut self, field_id: FormNodeId) -> Result<(), ()> {
629 self.list_clear_inner(field_id, None)
630 }
631
632 #[allow(clippy::result_unit_err)]
634 pub fn list_clear_for_handle(
635 &mut self,
636 field_id: FormNodeId,
637 generation: u64,
638 ) -> Result<(), ()> {
639 self.list_clear_inner(field_id, Some(generation))
640 }
641
642 #[allow(clippy::result_unit_err)]
644 pub fn list_add(
645 &mut self,
646 field_id: FormNodeId,
647 display: String,
648 save: Option<String>,
649 ) -> Result<(), ()> {
650 self.list_add_inner(field_id, None, display, save)
651 }
652
653 #[allow(clippy::result_unit_err)]
655 pub fn list_add_for_handle(
656 &mut self,
657 field_id: FormNodeId,
658 generation: u64,
659 display: String,
660 save: Option<String>,
661 ) -> Result<(), ()> {
662 self.list_add_inner(field_id, Some(generation), display, save)
663 }
664
665 pub fn bound_item_for_handle(
676 &mut self,
677 field_id: FormNodeId,
678 generation: u64,
679 display_value: String,
680 ) -> String {
681 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
682 if !self.handle_is_live(field_id, generation) {
683 return display_value;
684 }
685 let Some(form) = self.form_ref() else {
686 return display_value;
687 };
688 if !matches!(form.get(field_id).node_type, FormNodeType::Field { .. }) {
689 return display_value;
690 }
691 let meta = form.meta(field_id);
692 for (display, save) in &meta.runtime_listbox_items {
693 if display == &display_value {
694 return save.clone();
695 }
696 }
697 for (idx, display) in meta.display_items.iter().enumerate() {
698 if display == &display_value {
699 return meta
700 .save_items
701 .get(idx)
702 .cloned()
703 .unwrap_or_else(|| display_value.clone());
704 }
705 }
706 display_value
707 }
708
709 pub fn num_pages(&mut self) -> u32 {
711 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
712 self.static_page_count
713 }
714
715 pub fn metadata_binding_error(&mut self) {
717 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
718 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
719 }
720
721 pub fn metadata_resolve_failure(&mut self) {
723 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
724 self.metadata.resolve_failures = self.metadata.resolve_failures.saturating_add(1);
725 }
726
727 fn consume_resolve_call(&mut self) -> bool {
728 if self.resolve_count_this_script >= MAX_RESOLVE_CALLS_PER_SCRIPT {
729 return false;
730 }
731 self.resolve_count_this_script = self.resolve_count_this_script.saturating_add(1);
732 true
733 }
734
735 fn resolve_path(&mut self, path: &str) -> ResolveOutcome {
736 if !self.consume_resolve_call() {
737 return ResolveOutcome::BindingError;
738 }
739
740 let Some(form) = self.form_ref() else {
741 return ResolveOutcome::BindingError;
742 };
743 let Some(current_id) = self.current_id else {
744 return ResolveOutcome::BindingError;
745 };
746 if current_id.0 >= form.nodes.len() || self.root_id.0 >= form.nodes.len() {
747 return ResolveOutcome::BindingError;
748 }
749
750 let normalized = normalize_resolve_path(path.trim());
751 let mut expr = match parse_som(&normalized) {
752 Ok(expr) => expr,
753 Err(_) => return ResolveOutcome::BindingError,
754 };
755 if expr.segments.len() > MAX_SOM_DEPTH {
756 return ResolveOutcome::BindingError;
757 }
758 if matches!(
759 expr.segments.last().map(|segment| &segment.selector),
760 Some(SomSelector::Name(name)) if name == "rawValue"
761 ) {
762 expr.segments.pop();
763 }
764
765 let parents = build_parent_map(form, self.root_id);
766 let resolver = HostSomResolver {
767 form,
768 root_id: self.root_id,
769 parents: &parents,
770 current_id,
771 };
772 match resolver.resolve_expression(&expr) {
773 Some(nodes) if !nodes.is_empty() => ResolveOutcome::Ok(nodes),
774 _ => ResolveOutcome::NoMatch,
775 }
776 }
777
778 fn resolve_implicit_inner(&mut self, current_id: FormNodeId, name: &str) -> ResolveOutcome {
779 let name = name.trim();
780 if name.is_empty() || !self.consume_resolve_call() {
781 return ResolveOutcome::BindingError;
782 }
783
784 let Some(form) = self.form_ref() else {
785 return ResolveOutcome::BindingError;
786 };
787 if current_id.0 >= form.nodes.len() || self.root_id.0 >= form.nodes.len() {
788 return ResolveOutcome::BindingError;
789 }
790
791 let parents = build_parent_map(form, self.root_id);
792 resolve_implicit_candidates_in_scope(form, &parents, current_id, name)
793 }
794
795 fn resolve_child_inner(&mut self, parent_id: FormNodeId, name: &str) -> ResolveOutcome {
796 self.resolve_child_candidates_inner(&[parent_id], name)
797 }
798
799 fn resolve_child_candidates_inner(
800 &mut self,
801 parent_ids: &[FormNodeId],
802 name: &str,
803 ) -> ResolveOutcome {
804 let name = name.trim();
805 if name.is_empty() || !self.consume_resolve_call() {
806 return ResolveOutcome::BindingError;
807 }
808
809 let Some(form) = self.form_ref() else {
810 return ResolveOutcome::BindingError;
811 };
812 if parent_ids.is_empty()
813 || parent_ids
814 .iter()
815 .any(|node_id| node_id.0 >= form.nodes.len())
816 {
817 return ResolveOutcome::BindingError;
818 }
819
820 let mut direct = Vec::new();
821 for &parent_id in parent_ids {
822 for &child_id in &form.get(parent_id).children {
823 if form.get(child_id).name == name {
824 push_unique_candidate(&mut direct, child_id);
825 if direct.len() >= MAX_RESOLVE_CANDIDATES {
826 return ResolveOutcome::Ok(direct);
827 }
828 }
829 }
830 }
831 if !direct.is_empty() {
832 return ResolveOutcome::Ok(direct);
833 }
834
835 let mut descendants = Vec::new();
836 for &parent_id in parent_ids {
837 let mut local =
838 collect_named_descendant_candidates(form, parent_id, name, MAX_SOM_DEPTH);
839 order_candidates(form, &mut local);
840 for node_id in local {
841 push_unique_candidate(&mut descendants, node_id);
842 if descendants.len() >= MAX_RESOLVE_CANDIDATES {
843 return ResolveOutcome::Ok(descendants);
844 }
845 }
846 }
847 if descendants.is_empty() {
848 ResolveOutcome::NoMatch
849 } else {
850 ResolveOutcome::Ok(descendants)
851 }
852 }
853
854 fn resolve_scoped_candidates_inner(
855 &mut self,
856 scope_ids: &[FormNodeId],
857 name: &str,
858 ) -> ResolveOutcome {
859 let name = name.trim();
860 if name.is_empty() || !self.consume_resolve_call() {
861 return ResolveOutcome::BindingError;
862 }
863
864 let Some(form) = self.form_ref() else {
865 return ResolveOutcome::BindingError;
866 };
867 if scope_ids.is_empty()
868 || self.root_id.0 >= form.nodes.len()
869 || scope_ids
870 .iter()
871 .any(|node_id| node_id.0 >= form.nodes.len())
872 {
873 return ResolveOutcome::BindingError;
874 }
875
876 let parents = build_parent_map(form, self.root_id);
877 let mut out = Vec::new();
878 for &scope_id in scope_ids {
879 if let ResolveOutcome::Ok(nodes) =
880 resolve_implicit_candidates_in_scope(form, &parents, scope_id, name)
881 {
882 for node_id in nodes {
883 push_unique_candidate(&mut out, node_id);
884 if out.len() >= MAX_RESOLVE_CANDIDATES {
885 return ResolveOutcome::Ok(out);
886 }
887 }
888 }
889 }
890 if out.is_empty() {
891 ResolveOutcome::NoMatch
892 } else {
893 ResolveOutcome::Ok(out)
894 }
895 }
896
897 fn instance_count_inner(&mut self, parent_id: FormNodeId, generation: Option<u64>) -> u32 {
898 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
899 let Some(run) = self.read_instance_run(parent_id, generation) else {
900 return 0;
901 };
902 run.nodes.len() as u32
903 }
904
905 fn instance_index_inner(&mut self, node_id: FormNodeId, generation: Option<u64>) -> u32 {
906 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
907 let Some(run) = self.read_instance_run(node_id, generation) else {
908 return 0;
909 };
910 run.nodes
911 .iter()
912 .position(|candidate| *candidate == node_id)
913 .unwrap_or(0) as u32
914 }
915
916 fn instance_set_inner(
917 &mut self,
918 parent_id: FormNodeId,
919 generation: Option<u64>,
920 n: u32,
921 ) -> Result<u32, ()> {
922 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
923 if !self.write_activity_allowed()
924 || self.mutation_count_this_doc >= MAX_MUTATIONS_PER_DOC
925 || !self.consume_resolve_call()
926 {
927 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
928 return Err(());
929 }
930
931 let Some(run) = self.live_instance_run(parent_id, generation) else {
932 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
933 return Err(());
934 };
935 let Some(target_count) = self.clamped_instance_count(run.prototype_id, n) else {
936 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
937 return Err(());
938 };
939
940 let target_count = target_count as usize;
941 let prototype_id = run.prototype_id;
942 let parent_id = run.parent_id;
943 let first_pos = run.first_position;
944 let Some(prototype_name) = self
945 .form_ref()
946 .and_then(|form| form.nodes.get(prototype_id.0))
947 .map(|node| node.name.clone())
948 else {
949 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
950 return Err(());
951 };
952 let remove_ids = run.nodes;
953
954 let mut new_ids = Vec::with_capacity(target_count);
955 if target_count > 0 {
956 self.normalize_instance_occurrence(prototype_id);
957 new_ids.push(prototype_id);
958 for _ in 1..target_count {
959 let cloned_id = self.clone_subtree(prototype_id)?;
960 new_ids.push(cloned_id);
961 }
962 }
963
964 let Some(form) = self.form_mut() else {
965 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
966 return Err(());
967 };
968 let parent = form.get_mut(parent_id);
969 parent
970 .children
971 .retain(|child_id| !remove_ids.contains(child_id));
972 let insert_pos = first_pos.min(parent.children.len());
973 for (offset, node_id) in new_ids.iter().copied().enumerate() {
974 parent.children.insert(insert_pos + offset, node_id);
975 }
976
977 let key = (parent_id, prototype_name);
978 if target_count == 0 {
979 self.zero_instance_runs.insert(key, self.generation);
980 } else {
981 self.zero_instance_runs.remove(&key);
982 }
983 self.record_instance_write();
984 Ok(target_count as u32)
985 }
986
987 fn instance_add_inner(
988 &mut self,
989 parent_id: FormNodeId,
990 generation: Option<u64>,
991 ) -> Result<FormNodeId, ()> {
992 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
993 if !self.write_activity_allowed()
994 || self.mutation_count_this_doc >= MAX_MUTATIONS_PER_DOC
995 || !self.consume_resolve_call()
996 {
997 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
998 return Err(());
999 }
1000
1001 let Some(run) = self.live_instance_run(parent_id, generation) else {
1002 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1003 return Err(());
1004 };
1005 let zero_key = self
1006 .form_ref()
1007 .and_then(|form| form.nodes.get(run.prototype_id.0))
1008 .map(|node| (run.parent_id, node.name.clone()));
1009 let Some(max_allowed) = self.max_instances_for(run.prototype_id) else {
1010 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1011 return Err(());
1012 };
1013 if run.nodes.len() as u32 >= max_allowed {
1014 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1015 return Err(());
1016 }
1017
1018 let cloned_id = self.clone_subtree(run.prototype_id)?;
1019 let Some(form) = self.form_mut() else {
1020 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1021 return Err(());
1022 };
1023 form.get_mut(run.parent_id)
1024 .children
1025 .insert(run.last_position + 1, cloned_id);
1026
1027 if let Some(key) = zero_key {
1028 self.zero_instance_runs.remove(&key);
1029 }
1030 self.record_instance_write();
1031 Ok(cloned_id)
1032 }
1033
1034 fn instance_remove_inner(
1035 &mut self,
1036 parent_id: FormNodeId,
1037 generation: Option<u64>,
1038 index: u32,
1039 ) -> Result<(), ()> {
1040 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
1041 if !self.write_activity_allowed()
1042 || self.mutation_count_this_doc >= MAX_MUTATIONS_PER_DOC
1043 || !self.consume_resolve_call()
1044 {
1045 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1046 return Err(());
1047 }
1048
1049 let Some(run) = self.live_instance_run(parent_id, generation) else {
1050 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1051 return Err(());
1052 };
1053 let zero_key = self
1054 .form_ref()
1055 .and_then(|form| form.nodes.get(run.prototype_id.0))
1056 .map(|node| (run.parent_id, node.name.clone()));
1057 let min_allowed = self
1058 .form_ref()
1059 .and_then(|form| form.nodes.get(run.prototype_id.0))
1060 .map(|node| node.occur.min)
1061 .unwrap_or(1);
1062 if run.nodes.len() as u32 <= min_allowed {
1063 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1064 return Err(());
1065 }
1066 let Some(remove_position) = run.positions.get(index as usize).copied() else {
1067 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1068 return Err(());
1069 };
1070
1071 let Some(form) = self.form_mut() else {
1072 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1073 return Err(());
1074 };
1075 form.get_mut(run.parent_id).children.remove(remove_position);
1076
1077 if let Some(key) = zero_key {
1078 if run.nodes.len() == 1 {
1079 self.zero_instance_runs.insert(key, self.generation);
1080 } else {
1081 self.zero_instance_runs.remove(&key);
1082 }
1083 }
1084 self.record_instance_write();
1085 Ok(())
1086 }
1087
1088 fn read_instance_run(
1089 &mut self,
1090 node_id: FormNodeId,
1091 generation: Option<u64>,
1092 ) -> Option<InstanceRun> {
1093 if !self.consume_resolve_call() {
1094 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1095 return None;
1096 }
1097 let Some(form) = self.form_ref() else {
1098 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1099 return None;
1100 };
1101 if generation.is_some_and(|value| value != self.generation) {
1102 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1103 return None;
1104 }
1105 if node_id.0 >= form.nodes.len() || self.root_id.0 >= form.nodes.len() {
1106 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1107 return None;
1108 }
1109
1110 let parents = build_parent_map(form, self.root_id);
1111 if !parents.contains_key(&node_id) {
1112 if node_id == self.root_id {
1113 return Some(InstanceRun {
1114 parent_id: node_id,
1115 positions: vec![0],
1116 nodes: vec![node_id],
1117 prototype_id: node_id,
1118 first_position: 0,
1119 last_position: 0,
1120 });
1121 }
1122 return None;
1123 }
1124
1125 build_instance_run(form, &parents, node_id)
1126 }
1127
1128 fn live_instance_run(
1129 &self,
1130 node_id: FormNodeId,
1131 generation: Option<u64>,
1132 ) -> Option<InstanceRun> {
1133 let form = self.form_ref()?;
1134 if generation.is_some_and(|value| value != self.generation)
1135 || node_id.0 >= form.nodes.len()
1136 || self.root_id.0 >= form.nodes.len()
1137 || !is_instance_node(&form.get(node_id).node_type)
1138 {
1139 return None;
1140 }
1141 let parents = build_parent_map(form, self.root_id);
1142 build_instance_run(form, &parents, node_id)
1143 }
1144
1145 fn clamped_instance_count(&self, prototype_id: FormNodeId, requested: u32) -> Option<u32> {
1146 let min_allowed = self.form_ref()?.get(prototype_id).occur.min;
1147 let max_allowed = self.max_instances_for(prototype_id)?;
1148 if min_allowed > max_allowed {
1149 return None;
1150 }
1151 Some(requested.clamp(min_allowed, max_allowed))
1152 }
1153
1154 fn max_instances_for(&self, prototype_id: FormNodeId) -> Option<u32> {
1155 let occur = &self.form_ref()?.get(prototype_id).occur;
1156 let max = occur.max.unwrap_or(u32::MAX);
1157 Some(max.min(MAX_INSTANCES_PER_SUBFORM))
1158 }
1159
1160 fn clone_subtree(&mut self, source_id: FormNodeId) -> Result<FormNodeId, ()> {
1161 let (mut new_node, mut new_meta, child_ids) = {
1162 let Some(form) = self.form_ref() else {
1163 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1164 return Err(());
1165 };
1166 if source_id.0 >= form.nodes.len() {
1167 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1168 return Err(());
1169 }
1170 (
1171 form.get(source_id).clone(),
1172 form.meta(source_id).clone(),
1173 form.get(source_id).children.clone(),
1174 )
1175 };
1176
1177 let mut new_children = Vec::with_capacity(child_ids.len());
1178 for child_id in child_ids {
1179 new_children.push(self.clone_subtree(child_id)?);
1180 }
1181 new_node.children = new_children;
1182 new_node.occur.initial = 1;
1185 new_meta.xfa_id = None;
1186
1187 let Some(form) = self.form_mut() else {
1188 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1189 return Err(());
1190 };
1191 Ok(form.add_node_with_meta(new_node, new_meta))
1192 }
1193
1194 fn normalize_instance_occurrence(&mut self, node_id: FormNodeId) {
1195 if let Some(form) = self.form_mut() {
1196 if let Some(node) = form.nodes.get_mut(node_id.0) {
1197 node.occur.initial = 1;
1200 }
1201 }
1202 }
1203
1204 fn record_instance_write(&mut self) {
1205 self.metadata.instance_writes = self.metadata.instance_writes.saturating_add(1);
1206 self.mutation_count_this_doc = self.mutation_count_this_doc.saturating_add(1);
1207 }
1208
1209 fn record_list_write(&mut self) {
1210 self.metadata.list_writes = self.metadata.list_writes.saturating_add(1);
1211 self.mutation_count_this_doc = self.mutation_count_this_doc.saturating_add(1);
1212 }
1213
1214 fn list_clear_inner(
1215 &mut self,
1216 field_id: FormNodeId,
1217 generation: Option<u64>,
1218 ) -> Result<(), ()> {
1219 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
1220 if !self.write_activity_allowed()
1221 || self.mutation_count_this_doc >= MAX_MUTATIONS_PER_DOC
1222 || !self.consume_resolve_call()
1223 {
1224 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1225 return Err(());
1226 }
1227 let current_generation = self.generation;
1228 let Some(form) = self.form_mut() else {
1229 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1230 return Err(());
1231 };
1232 if generation.is_some_and(|value| value != current_generation)
1233 || field_id.0 >= form.nodes.len()
1234 {
1235 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1236 return Err(());
1237 }
1238 if !matches!(form.get(field_id).node_type, FormNodeType::Field { .. }) {
1239 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1240 return Err(());
1241 }
1242 form.meta_mut(field_id).runtime_listbox_items.clear();
1243 self.record_list_write();
1244 Ok(())
1245 }
1246
1247 fn list_add_inner(
1248 &mut self,
1249 field_id: FormNodeId,
1250 generation: Option<u64>,
1251 display: String,
1252 save: Option<String>,
1253 ) -> Result<(), ()> {
1254 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
1255 if !self.write_activity_allowed()
1256 || self.mutation_count_this_doc >= MAX_MUTATIONS_PER_DOC
1257 || !self.consume_resolve_call()
1258 {
1259 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1260 return Err(());
1261 }
1262 let current_generation = self.generation;
1263 let Some(form) = self.form_mut() else {
1264 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1265 return Err(());
1266 };
1267 if generation.is_some_and(|value| value != current_generation)
1268 || field_id.0 >= form.nodes.len()
1269 {
1270 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1271 return Err(());
1272 }
1273 if !matches!(form.get(field_id).node_type, FormNodeType::Field { .. }) {
1274 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1275 return Err(());
1276 }
1277 let meta = form.meta_mut(field_id);
1278 if meta.runtime_listbox_items.len() >= MAX_ITEMS_PER_LISTBOX as usize {
1279 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1280 return Err(());
1281 }
1282 let save_value = save.unwrap_or_else(|| display.clone());
1283 meta.runtime_listbox_items.push((display, save_value));
1284 self.record_list_write();
1285 Ok(())
1286 }
1287
1288 fn write_activity_allowed(&self) -> bool {
1289 matches!(
1290 self.current_activity.as_deref(),
1291 Some("initialize")
1292 | Some("calculate")
1293 | Some("validate")
1294 | Some("docReady")
1295 | Some("layoutReady")
1296 )
1297 }
1298
1299 fn handle_is_live(&self, node_id: FormNodeId, generation: u64) -> bool {
1300 generation == self.generation
1301 && self
1302 .form_ref()
1303 .is_some_and(|form| node_id.0 < form.nodes.len())
1304 }
1305
1306 fn write_field_value(
1307 &mut self,
1308 node_id: FormNodeId,
1309 value: String,
1310 ) -> Option<(String, String)> {
1311 let form = self.form_mut()?;
1312 let node = form.nodes.get_mut(node_id.0)?;
1313 let FormNodeType::Field { value: field_value } = &mut node.node_type else {
1314 return None;
1315 };
1316 let before = field_value.clone();
1317 *field_value = value;
1318 Some((before, field_value.clone()))
1319 }
1320
1321 fn form_ref(&self) -> Option<&FormTree> {
1322 if self.form.is_null() {
1323 None
1324 } else {
1325 unsafe { self.form.as_ref() }
1329 }
1330 }
1331
1332 fn form_mut(&mut self) -> Option<&mut FormTree> {
1333 if self.form.is_null() {
1334 None
1335 } else {
1336 unsafe { self.form.as_mut() }
1339 }
1340 }
1341
1342 fn data_dom_ref(&self) -> Option<&DataDom> {
1344 self.data_dom.map(|ptr| unsafe { &*ptr })
1348 }
1349
1350 pub fn data_children(&mut self, raw_id: usize) -> Vec<usize> {
1353 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
1354 let result = {
1356 let Some(dom) = self.data_dom_ref() else {
1357 return Vec::new();
1358 };
1359 let id = DataNodeId::from_raw(raw_id);
1360 if dom.get(id).is_none() {
1361 return Vec::new();
1362 }
1363 dom.children(id)
1364 .iter()
1365 .take(MAX_RESOLVE_RESULTS)
1366 .map(|c| c.as_raw())
1367 .collect::<Vec<_>>()
1368 };
1369 self.metadata.data_reads = self.metadata.data_reads.saturating_add(1);
1370 result
1371 }
1372
1373 pub fn data_value(&mut self, raw_id: usize) -> Option<String> {
1376 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
1377 let result = {
1378 let dom = self.data_dom_ref()?;
1379 let id = DataNodeId::from_raw(raw_id);
1380 dom.get(id)?;
1381 dom.value(id).ok().map(|s| s.to_owned())
1382 };
1383 if result.is_some() {
1384 self.metadata.data_reads = self.metadata.data_reads.saturating_add(1);
1385 }
1386 result
1387 }
1388
1389 pub fn data_child_by_name(&mut self, parent_raw: usize, name: &str) -> Option<usize> {
1392 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
1393 let result = {
1394 let dom = self.data_dom_ref()?;
1395 let parent = DataNodeId::from_raw(parent_raw);
1396 dom.get(parent)?;
1397 dom.children_by_name(parent, name)
1398 .into_iter()
1399 .next()
1400 .map(|id| id.as_raw())
1401 };
1402 if result.is_some() {
1403 self.metadata.data_reads = self.metadata.data_reads.saturating_add(1);
1404 }
1405 result
1406 }
1407
1408 pub fn data_bound_record(
1411 &mut self,
1412 form_node_id: FormNodeId,
1413 generation: u64,
1414 ) -> Option<usize> {
1415 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
1416 if generation != self.generation {
1417 return None;
1418 }
1419 let form = self.form_ref()?;
1420 if form_node_id.0 >= form.nodes.len() {
1421 return None;
1422 }
1423 form.meta(form_node_id).bound_data_node
1424 }
1425
1426 pub fn data_resolve_node(&mut self, path: &str) -> Option<usize> {
1430 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
1431 if !self.consume_resolve_call() {
1432 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1433 return None;
1434 }
1435 {
1437 let dom = self.data_dom_ref()?;
1438 resolve_data_path(dom, path, None)
1439 .ok()?
1440 .into_iter()
1441 .next()
1442 .map(|id| id.as_raw())
1443 }
1444 }
1445
1446 pub fn data_resolve_nodes(&mut self, path: &str) -> Vec<usize> {
1449 self.metadata.host_calls = self.metadata.host_calls.saturating_add(1);
1450 if !self.consume_resolve_call() {
1451 self.metadata.binding_errors = self.metadata.binding_errors.saturating_add(1);
1452 return Vec::new();
1453 }
1454 {
1455 let Some(dom) = self.data_dom_ref() else {
1456 return Vec::new();
1457 };
1458 resolve_data_path(dom, path, None)
1459 .unwrap_or_default()
1460 .into_iter()
1461 .take(MAX_RESOLVE_RESULTS)
1462 .map(|id| id.as_raw())
1463 .collect()
1464 }
1465 }
1466}
1467
1468enum ResolveOutcome {
1469 Ok(Vec<FormNodeId>),
1470 NoMatch,
1471 BindingError,
1472}
1473
1474#[derive(Debug, Clone)]
1475struct InstanceRun {
1476 parent_id: FormNodeId,
1477 positions: Vec<usize>,
1478 nodes: Vec<FormNodeId>,
1479 prototype_id: FormNodeId,
1480 first_position: usize,
1481 last_position: usize,
1482}
1483
1484fn build_instance_run(
1485 form: &FormTree,
1486 parents: &HashMap<FormNodeId, FormNodeId>,
1487 node_id: FormNodeId,
1488) -> Option<InstanceRun> {
1489 let parent_id = parents.get(&node_id).copied()?;
1490 let name = form.get(node_id).name.clone();
1491 let parent = form.get(parent_id);
1492 let mut positions = Vec::new();
1493 let mut nodes = Vec::new();
1494 for (position, child_id) in parent.children.iter().copied().enumerate() {
1495 if form.get(child_id).name == name {
1496 positions.push(position);
1497 nodes.push(child_id);
1498 }
1499 }
1500 if !nodes.contains(&node_id) {
1501 return None;
1502 }
1503 Some(InstanceRun {
1504 parent_id,
1505 prototype_id: nodes[0],
1506 first_position: positions[0],
1507 last_position: *positions.last()?,
1508 positions,
1509 nodes,
1510 })
1511}
1512
1513fn is_instance_node(node_type: &FormNodeType) -> bool {
1514 matches!(
1515 node_type,
1516 FormNodeType::Root
1517 | FormNodeType::Subform
1518 | FormNodeType::Area
1519 | FormNodeType::ExclGroup
1520 | FormNodeType::SubformSet
1521 )
1522}
1523
1524fn normalize_resolve_path(path: &str) -> String {
1525 if let Some(rest) = path.strip_prefix("this.") {
1526 format!("$.{rest}")
1527 } else if path == "this" {
1528 "$".to_string()
1529 } else {
1530 path.to_string()
1531 }
1532}
1533
1534struct HostSomResolver<'a> {
1535 form: &'a FormTree,
1536 root_id: FormNodeId,
1537 parents: &'a HashMap<FormNodeId, FormNodeId>,
1538 current_id: FormNodeId,
1539}
1540
1541impl HostSomResolver<'_> {
1542 fn resolve_expression(&self, expr: &SomExpression) -> Option<Vec<FormNodeId>> {
1543 match expr.root {
1544 SomRoot::Data | SomRoot::Record | SomRoot::Template => None,
1545 SomRoot::CurrentContainer => {
1546 if expr.segments.is_empty() {
1547 Some(vec![self.current_id])
1548 } else {
1549 Some(self.follow_absolute(vec![self.current_id], &expr.segments))
1550 }
1551 }
1552 SomRoot::Form => {
1553 if expr.segments.is_empty() {
1554 Some(vec![self.root_id])
1555 } else {
1556 Some(self.follow_absolute(vec![self.root_id], &expr.segments))
1557 }
1558 }
1559 SomRoot::Xfa => {
1560 let segments = strip_xfa_form_prefix(&expr.segments);
1561 if segments.is_empty() {
1562 Some(vec![self.root_id])
1563 } else {
1564 Some(self.follow_absolute(vec![self.root_id], segments))
1565 }
1566 }
1567 SomRoot::Unqualified => {
1568 if expr.segments.is_empty() {
1569 Some(vec![self.current_id])
1570 } else {
1571 Some(self.follow_unqualified(&expr.segments))
1572 }
1573 }
1574 }
1575 }
1576
1577 fn follow_absolute(
1578 &self,
1579 mut current: Vec<FormNodeId>,
1580 segments: &[xfa_dom_resolver::som::SomSegment],
1581 ) -> Vec<FormNodeId> {
1582 for (idx, segment) in segments.iter().enumerate() {
1583 let allow_self = idx == 0;
1584 current = current
1585 .into_iter()
1586 .flat_map(|node_id| self.step_from_node(node_id, segment, allow_self))
1587 .collect();
1588 if current.is_empty() {
1589 break;
1590 }
1591 }
1592 current
1593 }
1594
1595 fn follow_unqualified(
1596 &self,
1597 segments: &[xfa_dom_resolver::som::SomSegment],
1598 ) -> Vec<FormNodeId> {
1599 let Some((first, rest)) = segments.split_first() else {
1600 return vec![self.current_id];
1601 };
1602
1603 let mut scope = Some(self.current_id);
1604 while let Some(scope_id) = scope {
1605 let anchors: Vec<_> = descendants_inclusive(self.form, scope_id)
1606 .into_iter()
1607 .filter(|node_id| self.node_matches_segment(*node_id, first))
1608 .collect();
1609 let matched = self.follow_remaining(anchors, rest);
1610 if !matched.is_empty() {
1611 return matched;
1612 }
1613 scope = self.parents.get(&scope_id).copied();
1614 }
1615
1616 let anchors: Vec<_> = descendants_inclusive(self.form, self.root_id)
1617 .into_iter()
1618 .filter(|node_id| self.node_matches_segment(*node_id, first))
1619 .collect();
1620 self.follow_remaining(anchors, rest)
1621 }
1622
1623 fn follow_remaining(
1624 &self,
1625 mut current: Vec<FormNodeId>,
1626 segments: &[xfa_dom_resolver::som::SomSegment],
1627 ) -> Vec<FormNodeId> {
1628 for segment in segments {
1629 current = current
1630 .into_iter()
1631 .flat_map(|node_id| self.step_from_node(node_id, segment, false))
1632 .collect();
1633 if current.is_empty() {
1634 break;
1635 }
1636 }
1637 current
1638 }
1639
1640 fn step_from_node(
1641 &self,
1642 node_id: FormNodeId,
1643 segment: &xfa_dom_resolver::som::SomSegment,
1644 allow_self: bool,
1645 ) -> Vec<FormNodeId> {
1646 if let SomSelector::Name(name) = &segment.selector {
1647 if name == ".." {
1648 if let Some(&parent_id) = self.parents.get(&node_id) {
1649 return apply_index_to_single(parent_id, segment.index);
1650 }
1651 return Vec::new();
1652 }
1653 }
1654
1655 if allow_self && self.node_matches_selector(node_id, &segment.selector) {
1656 return apply_index_to_single(node_id, segment.index);
1657 }
1658
1659 let matches: Vec<_> = self
1660 .form
1661 .get(node_id)
1662 .children
1663 .iter()
1664 .copied()
1665 .filter(|child_id| self.node_matches_selector(*child_id, &segment.selector))
1666 .collect();
1667
1668 apply_index(matches, segment.index)
1669 }
1670
1671 fn node_matches_segment(
1672 &self,
1673 node_id: FormNodeId,
1674 segment: &xfa_dom_resolver::som::SomSegment,
1675 ) -> bool {
1676 if !self.node_matches_selector(node_id, &segment.selector) {
1677 return false;
1678 }
1679
1680 match segment.index {
1681 SomIndex::All => true,
1682 SomIndex::None => self.sibling_position(node_id, &segment.selector) == Some(0),
1683 SomIndex::Specific(idx) => {
1684 self.sibling_position(node_id, &segment.selector) == Some(idx)
1685 }
1686 }
1687 }
1688
1689 fn sibling_position(&self, node_id: FormNodeId, selector: &SomSelector) -> Option<usize> {
1690 let Some(parent_id) = self.parents.get(&node_id).copied() else {
1691 return self.node_matches_selector(node_id, selector).then_some(0);
1692 };
1693
1694 self.form
1695 .get(parent_id)
1696 .children
1697 .iter()
1698 .copied()
1699 .filter(|candidate| self.node_matches_selector(*candidate, selector))
1700 .position(|candidate| candidate == node_id)
1701 }
1702
1703 fn node_matches_selector(&self, node_id: FormNodeId, selector: &SomSelector) -> bool {
1704 match selector {
1705 SomSelector::Name(name) => self.form.get(node_id).name == *name,
1706 SomSelector::Class(class_name) => self.node_matches_class(node_id, class_name),
1707 SomSelector::AllChildren => true,
1708 }
1709 }
1710
1711 fn node_matches_class(&self, node_id: FormNodeId, class_name: &str) -> bool {
1712 let class_name = class_name.to_ascii_lowercase();
1713 match class_name.as_str() {
1714 "subform" => matches!(
1715 self.form.get(node_id).node_type,
1716 FormNodeType::Root | FormNodeType::Subform
1717 ),
1718 "pageset" => matches!(self.form.get(node_id).node_type, FormNodeType::PageSet),
1719 "pagearea" => matches!(
1720 self.form.get(node_id).node_type,
1721 FormNodeType::PageArea { .. }
1722 ),
1723 "field" => matches!(self.form.get(node_id).node_type, FormNodeType::Field { .. }),
1724 "draw" => matches!(
1725 self.form.get(node_id).node_type,
1726 FormNodeType::Draw(_) | FormNodeType::Image { .. }
1727 ),
1728 "exclgroup" => self.form.meta(node_id).group_kind == GroupKind::ExclusiveChoice,
1729 _ => false,
1730 }
1731 }
1732}
1733
1734fn strip_xfa_form_prefix(
1735 segments: &[xfa_dom_resolver::som::SomSegment],
1736) -> &[xfa_dom_resolver::som::SomSegment] {
1737 match segments.first() {
1738 Some(segment)
1739 if matches!(&segment.selector, SomSelector::Name(name) if name == "form")
1740 && matches!(segment.index, SomIndex::None) =>
1741 {
1742 &segments[1..]
1743 }
1744 _ => segments,
1745 }
1746}
1747
1748fn apply_index(matches: Vec<FormNodeId>, index: SomIndex) -> Vec<FormNodeId> {
1749 match index {
1750 SomIndex::None => matches.into_iter().take(1).collect(),
1751 SomIndex::Specific(idx) => matches.get(idx).copied().into_iter().collect(),
1752 SomIndex::All => matches,
1753 }
1754}
1755
1756fn apply_index_to_single(node_id: FormNodeId, index: SomIndex) -> Vec<FormNodeId> {
1757 match index {
1758 SomIndex::None | SomIndex::Specific(0) | SomIndex::All => vec![node_id],
1759 SomIndex::Specific(_) => Vec::new(),
1760 }
1761}
1762
1763fn descendants_inclusive(form: &FormTree, root_id: FormNodeId) -> Vec<FormNodeId> {
1764 let mut out = Vec::new();
1765 collect_descendants(form, root_id, &mut out);
1766 out
1767}
1768
1769fn collect_descendants(form: &FormTree, node_id: FormNodeId, out: &mut Vec<FormNodeId>) {
1770 out.push(node_id);
1771 for &child_id in &form.get(node_id).children {
1772 collect_descendants(form, child_id, out);
1773 }
1774}
1775
1776const MAX_RESOLVE_CANDIDATES: usize = 32;
1781
1782fn collect_named_descendant_candidates(
1802 form: &FormTree,
1803 scope_id: FormNodeId,
1804 name: &str,
1805 max_depth: usize,
1806) -> Vec<FormNodeId> {
1807 let mut candidates: Vec<FormNodeId> = Vec::new();
1808 find_named_descendant_inner(form, scope_id, name, 0, max_depth, &mut candidates);
1809 candidates
1810}
1811
1812fn order_candidates(form: &FormTree, candidates: &mut [FormNodeId]) {
1813 candidates.sort_by(|left, right| {
1823 let left_is_field = matches!(form.get(*left).node_type, FormNodeType::Field { .. });
1824 let right_is_field = matches!(form.get(*right).node_type, FormNodeType::Field { .. });
1825 match (left_is_field, right_is_field) {
1826 (true, false) => std::cmp::Ordering::Less,
1827 (false, true) => std::cmp::Ordering::Greater,
1828 (true, true) => std::cmp::Ordering::Equal,
1829 (false, false) => form
1830 .get(*right)
1831 .children
1832 .len()
1833 .cmp(&form.get(*left).children.len()),
1834 }
1835 });
1836}
1837
1838fn push_unique_candidate(candidates: &mut Vec<FormNodeId>, node_id: FormNodeId) {
1839 if candidates.len() < MAX_RESOLVE_CANDIDATES && !candidates.contains(&node_id) {
1840 candidates.push(node_id);
1841 }
1842}
1843
1844fn resolve_implicit_candidates_in_scope(
1845 form: &FormTree,
1846 parents: &HashMap<FormNodeId, FormNodeId>,
1847 current_id: FormNodeId,
1848 name: &str,
1849) -> ResolveOutcome {
1850 let mut scope = Some(current_id);
1855 let mut depth = 0usize;
1856 while let Some(scope_id) = scope {
1857 if depth > MAX_SOM_DEPTH {
1858 return ResolveOutcome::BindingError;
1859 }
1860 if scope_id.0 >= form.nodes.len() {
1861 return ResolveOutcome::BindingError;
1862 }
1863 let mut candidates =
1864 collect_named_descendant_candidates(form, scope_id, name, MAX_SOM_DEPTH);
1865 if !candidates.is_empty() {
1866 order_candidates(form, &mut candidates);
1867 if !form.get(candidates[0]).children.is_empty() {
1868 return ResolveOutcome::Ok(candidates);
1869 }
1870 }
1871 scope = parents.get(&scope_id).copied();
1872 depth += 1;
1873 }
1874
1875 let mut scope = Some(current_id);
1878 let mut depth = 0usize;
1879 while let Some(scope_id) = scope {
1880 if depth > MAX_SOM_DEPTH {
1881 return ResolveOutcome::BindingError;
1882 }
1883 if scope_id.0 >= form.nodes.len() {
1884 return ResolveOutcome::BindingError;
1885 }
1886 if form.get(scope_id).name == name {
1887 return ResolveOutcome::Ok(vec![scope_id]);
1888 }
1889 scope = parents.get(&scope_id).copied();
1890 depth += 1;
1891 }
1892
1893 let mut scope = Some(current_id);
1895 let mut depth = 0usize;
1896 while let Some(scope_id) = scope {
1897 if depth > MAX_SOM_DEPTH {
1898 return ResolveOutcome::BindingError;
1899 }
1900 if scope_id.0 >= form.nodes.len() {
1901 return ResolveOutcome::BindingError;
1902 }
1903 let mut candidates =
1904 collect_named_descendant_candidates(form, scope_id, name, MAX_SOM_DEPTH);
1905 if !candidates.is_empty() {
1906 order_candidates(form, &mut candidates);
1907 return ResolveOutcome::Ok(candidates);
1908 }
1909 scope = parents.get(&scope_id).copied();
1910 depth += 1;
1911 }
1912
1913 ResolveOutcome::NoMatch
1914}
1915
1916fn find_named_descendant_inner(
1917 form: &FormTree,
1918 node_id: FormNodeId,
1919 name: &str,
1920 depth: usize,
1921 max_depth: usize,
1922 candidates: &mut Vec<FormNodeId>,
1923) {
1924 if depth >= max_depth || candidates.len() >= MAX_RESOLVE_CANDIDATES {
1925 return;
1926 }
1927 for &child_id in &form.get(node_id).children {
1928 if candidates.len() >= MAX_RESOLVE_CANDIDATES {
1929 return;
1930 }
1931 if form.get(child_id).name == name {
1932 candidates.push(child_id);
1933 } else {
1937 find_named_descendant_inner(form, child_id, name, depth + 1, max_depth, candidates);
1938 }
1939 }
1940}
1941
1942fn build_parent_map(form: &FormTree, root_id: FormNodeId) -> HashMap<FormNodeId, FormNodeId> {
1943 let mut parents = HashMap::new();
1944 populate_parent_map(form, root_id, &mut parents);
1945 parents
1946}
1947
1948fn populate_parent_map(
1949 form: &FormTree,
1950 node_id: FormNodeId,
1951 parents: &mut HashMap<FormNodeId, FormNodeId>,
1952) {
1953 for &child_id in &form.get(node_id).children {
1954 parents.insert(child_id, node_id);
1955 populate_parent_map(form, child_id, parents);
1956 }
1957}
1958
1959fn parse_nonnegative_occur_value(value: &str) -> Option<u32> {
1960 let parsed = value.trim().parse::<u64>().ok()?;
1961 u32::try_from(parsed).ok()
1962}
1963
1964fn parse_max_occur_value(value: &str) -> Option<Option<u32>> {
1965 let trimmed = value.trim();
1966 if trimmed == "-1" {
1967 return Some(None);
1968 }
1969 parse_nonnegative_occur_value(trimmed).map(Some)
1970}
1971
1972fn clamp_occur_to_i32(value: u32) -> i32 {
1973 value.min(i32::MAX as u32) as i32
1974}
1975
1976#[cfg(test)]
1977mod tests {
1978 use super::*;
1979 use xfa_layout_engine::form::{FormNode, Occur};
1980 use xfa_layout_engine::text::FontMetrics;
1981 use xfa_layout_engine::types::{BoxModel, LayoutStrategy};
1982
1983 fn add_node(tree: &mut FormTree, name: &str, node_type: FormNodeType) -> FormNodeId {
1984 tree.add_node(FormNode {
1985 name: name.to_string(),
1986 node_type,
1987 box_model: BoxModel::default(),
1988 layout: LayoutStrategy::TopToBottom,
1989 children: Vec::new(),
1990 occur: Occur::once(),
1991 font: FontMetrics::default(),
1992 calculate: None,
1993 validate: None,
1994 column_widths: Vec::new(),
1995 col_span: 1,
1996 })
1997 }
1998
1999 #[test]
2000 fn raw_value_get_set_and_generation_guard() {
2001 let mut tree = FormTree::new();
2002 let root = add_node(&mut tree, "root", FormNodeType::Root);
2003 let field = add_node(
2004 &mut tree,
2005 "Field1",
2006 FormNodeType::Field {
2007 value: "old".to_string(),
2008 },
2009 );
2010 tree.get_mut(root).children = vec![field];
2011
2012 let mut host = HostBindings::new();
2013 host.reset_per_document();
2014 host.set_form_handle(&mut tree as *mut FormTree, root);
2015 host.reset_per_script(field, Some("calculate"));
2016 let generation = host.generation();
2017
2018 assert_eq!(
2019 host.get_raw_value(field, generation),
2020 Some("old".to_string())
2021 );
2022 assert!(host.set_raw_value(field, "new".to_string(), generation));
2023 assert_eq!(
2024 host.get_raw_value(field, generation),
2025 Some("new".to_string())
2026 );
2027
2028 host.reset_per_document();
2029 assert_eq!(host.get_raw_value(field, generation), None);
2030 }
2031
2032 #[test]
2033 fn resolve_node_rejects_over_depth() {
2034 let mut tree = FormTree::new();
2035 let root = add_node(&mut tree, "root", FormNodeType::Root);
2036 let field = add_node(
2037 &mut tree,
2038 "Field1",
2039 FormNodeType::Field {
2040 value: String::new(),
2041 },
2042 );
2043 tree.get_mut(root).children = vec![field];
2044
2045 let mut host = HostBindings::new();
2046 host.reset_per_document();
2047 host.set_form_handle(&mut tree as *mut FormTree, root);
2048 host.reset_per_script(root, Some("calculate"));
2049 let long_path = (0..=MAX_SOM_DEPTH)
2050 .map(|idx| format!("n{idx}"))
2051 .collect::<Vec<_>>()
2052 .join(".");
2053
2054 assert_eq!(host.resolve_node(&long_path), None);
2055 assert_eq!(host.take_metadata().binding_errors, 1);
2056 }
2057}