structured_pades/permissions/
placement.rs1use super::Transforms;
4use crate::{
5 document::{Document, Graph},
6 error::{Error, ErrorKind, ReadFailure, Syntax},
7 fields::Fields,
8 model::admit,
9 object::Type,
10 range::RangeSource,
11 signature::Signature,
12};
13use structured_asn1::memory::Work;
14
15pub struct Placement {
17 field: Option<usize>,
18 certification: bool,
19 first: bool,
20 permissions: Option<bool>,
21 complete: bool,
22}
23impl Placement {
24 #[must_use]
26 pub fn field(&self) -> Option<usize> {
27 self.field
28 }
29 #[must_use]
31 pub fn is_certification(&self) -> bool {
32 self.certification
33 }
34 #[must_use]
36 pub fn is_first_signed_field(&self) -> bool {
37 self.first
38 }
39 #[must_use]
42 pub fn catalog_permission_binding(&self) -> Option<bool> {
43 self.permissions
44 }
45 #[must_use]
47 pub fn all_requirements_met(&self) -> bool {
48 self.complete
49 }
50}
51
52impl<'s, S: RangeSource> Document<'s, S> {
53 pub fn signature_placement<W: Work>(
58 &self,
59 signature: Signature<'_, 's, S::Document, S::Generation>,
60 graph: &Graph<'s, S::Document, S::Generation>,
61 fields: &Fields<'_, 's, S::Document, S::Generation>,
62 transforms: &Transforms,
63 operation: &W,
64 ) -> Result<Placement, ReadFailure<S::Error>> {
65 let work = self.session.query(operation);
66 let location = signature.location();
67 self.check(&work, location)?;
68 if !core::ptr::eq(fields.graph, graph)
69 || !core::ptr::eq(graph.session, self.session)
70 || graph.stamp != self.stamp
71 || transforms.location() != location
72 {
73 return Err(Error {
74 kind: ErrorKind::Foreign,
75 location,
76 }
77 .into());
78 }
79 let field = fields.signature(location, &work)?;
80 let certification = transforms.permission().is_some();
81 let mut first = true;
82 for (ordinal, entry) in fields.values().iter().enumerate() {
83 admit(&work, location, 1)?;
84 if !entry.is_signature() || Some(ordinal) == field {
85 continue;
86 }
87 let Some(value) = fields.value(ordinal, &work)? else {
88 continue;
89 };
90 if value.direct().kind() == Type::Null {
91 continue;
92 }
93 if value.direct().kind() != Type::Dictionary {
94 return Err(Error {
95 kind: ErrorKind::Syntax(Syntax::Dictionary),
96 location: value.direct().location(),
97 }
98 .into());
99 }
100 if let Some(kind) = value.get(b"Type", &work)?
103 && kind.direct().name_equals(b"DocTimeStamp", &work)?
104 {
105 continue;
106 }
107 first = false;
108 }
109 let permissions = if let Some(perms) = graph.root().get(b"Perms", &work)? {
110 perms
111 .get(b"DocMDP", &work)?
112 .map(|value| value.direct().location() == location)
113 } else {
114 None
115 };
116 let complete = field.is_some()
117 && (!certification || first)
118 && match permissions {
119 Some(true) => certification,
120 Some(false) => !certification,
121 None => true,
122 };
123 self.check(&work, location)?;
124 Ok(Placement {
125 field,
126 certification,
127 first,
128 permissions,
129 complete,
130 })
131 }
132}