1use crate::{
4 document::{Document, Graph, GraphObject},
5 error::{Error, ErrorKind, ReadFailure, Syntax},
6 model::admit,
7 range::RangeSource,
8 source::Location,
9};
10use structured_asn1::memory::{HashWork, Memory, MemoryError, OwnedText, OwnedVec, Work};
11
12#[derive(Clone, Copy, PartialEq, Eq, Hash)]
13struct Position {
14 owner: usize,
15 node: usize,
16}
17impl HashWork for Position {
18 fn hash_work(&self) -> Result<u64, MemoryError> {
19 Ok(2)
20 }
21}
22
23pub struct Field<'g, 's, D, G> {
25 pub(crate) object: GraphObject<'g, 's, D, G>,
26 pub(crate) name: OwnedText,
27 pub(crate) signature: bool,
28 pub(crate) parent: Option<usize>,
29}
30
31impl<'g, 's, D: Copy + Eq, G: Copy + Eq> Field<'g, 's, D, G> {
32 #[must_use]
34 pub fn name(&self) -> &str {
35 self.name.as_str()
36 }
37 #[must_use]
39 pub fn object(&self) -> GraphObject<'g, 's, D, G> {
40 self.object
41 }
42 #[must_use]
44 pub fn is_signature(&self) -> bool {
45 self.signature
46 }
47 #[must_use]
49 pub fn parent(&self) -> Option<usize> {
50 self.parent
51 }
52}
53
54pub struct Fields<'g, 's, D, G> {
57 pub(crate) graph: &'g Graph<'s, D, G>,
58 pub(crate) values: OwnedVec<Field<'g, 's, D, G>, Memory>,
59 index: OwnedVec<usize, Memory>,
60}
61
62impl<'g, 's, D: Copy + Eq, G: Copy + Eq> Fields<'g, 's, D, G> {
63 #[must_use]
65 pub fn values(&self) -> &[Field<'g, 's, D, G>] {
66 &self.values
67 }
68
69 pub fn get(&self, name: &str, operation: &impl Work) -> crate::Result<Option<usize>> {
71 let work = self.graph.session.query(operation);
72 let mut low = 0;
73 let mut high = self.index.len();
74 while low < high {
75 let middle = low + (high - low) / 2;
76 let field = &self.values[self.index[middle]];
77 admit(
78 &work,
79 field.object.direct().location(),
80 name.len().min(field.name.len()) as u64 + 1,
81 )?;
82 match field.name().cmp(name) {
83 core::cmp::Ordering::Less => low = middle + 1,
84 core::cmp::Ordering::Greater => high = middle,
85 core::cmp::Ordering::Equal => return Ok(Some(self.index[middle])),
86 }
87 }
88 Ok(None)
89 }
90
91 pub fn value(
94 &self,
95 ordinal: usize,
96 operation: &impl Work,
97 ) -> crate::Result<Option<GraphObject<'g, 's, D, G>>> {
98 self.inherited(ordinal, b"V", operation)
99 }
100
101 pub(crate) fn inherited(
102 &self,
103 ordinal: usize,
104 key: &[u8],
105 operation: &impl Work,
106 ) -> crate::Result<Option<GraphObject<'g, 's, D, G>>> {
107 let work = self.graph.session.query(operation);
108 let mut next = Some(ordinal);
109 while let Some(index) = next {
110 let field = self.values.get(index).ok_or(Error {
111 kind: ErrorKind::Foreign,
112 location: self.graph.root().direct().location(),
113 })?;
114 admit(&work, field.object.direct().location(), 1)?;
115 if let Some(value) = field.object.get(key, &work)?
116 && value.direct().kind() != crate::object::Type::Null
117 {
118 return Ok(Some(value));
119 }
120 next = field.parent;
121 }
122 Ok(None)
123 }
124
125 pub fn signature(
128 &self,
129 location: Location,
130 operation: &impl Work,
131 ) -> crate::Result<Option<usize>> {
132 let mut result = None;
133 for (ordinal, field) in self.values.iter().enumerate() {
134 admit(operation, location, 1)?;
135 if !field.signature {
136 continue;
137 }
138 if field
139 .object
140 .get(b"V", operation)?
141 .is_some_and(|value| value.direct().location() == location)
142 {
143 if result.is_some() {
144 return Err(Error {
145 kind: ErrorKind::Ambiguous(Syntax::Dictionary),
146 location,
147 });
148 }
149 result = Some(ordinal);
150 }
151 }
152 Ok(result)
153 }
154}
155
156struct Pending<'g, 's, D, G> {
157 object: GraphObject<'g, 's, D, G>,
158 parent: Option<usize>,
159 signature: bool,
160}
161
162fn ordered<D: Copy + Eq, G: Copy + Eq, W: Work>(
163 values: &[Field<'_, '_, D, G>],
164 location: Location,
165 work: &W,
166) -> crate::Result<OwnedVec<usize, W>> {
167 let mut ordered = work.vector();
168 for (ordinal, field) in values.iter().enumerate() {
169 admit(work, field.object.direct().location(), 1)?;
170 if !field.name.is_empty() {
171 ordered.try_push(ordinal).map_err(|cause| Error {
172 kind: ErrorKind::Resource(cause),
173 location,
174 })?;
175 }
176 }
177 ordered
178 .try_sort_unstable_by(|&a, &b| {
179 let first = values[a].name();
180 let second = values[b].name();
181 admit(
182 work,
183 values[b].object.direct().location(),
184 first.len().min(second.len()) as u64 + 1,
185 )?;
186 Ok::<_, Error>(first.cmp(second))
187 })
188 .map_err(|cause| match cause {
189 structured_asn1::memory::SortError::Resource(cause) => Error {
190 kind: ErrorKind::Resource(cause),
191 location,
192 },
193 structured_asn1::memory::SortError::Comparison(cause) => cause,
194 })?;
195 for pair in ordered.windows(2) {
196 admit(
197 work,
198 location,
199 values[pair[0]].name.len().min(values[pair[1]].name.len()) as u64 + 1,
200 )?;
201 if values[pair[0]].name == values[pair[1]].name {
202 return Err(Error {
203 kind: ErrorKind::Ambiguous(Syntax::Dictionary),
204 location: values[pair[1]].object.direct().location(),
205 });
206 }
207 }
208 Ok(ordered)
209}
210
211fn seed<'g, 's, D: Copy + Eq, G: Copy + Eq, W: Work>(
212 graph: &'g Graph<'s, D, G>,
213 pending: &mut OwnedVec<Pending<'g, 's, D, G>, W>,
214 location: Location,
215 work: &impl Work,
216) -> crate::Result<()> {
217 if let Some(form) = graph.root().get(b"AcroForm", work)?
218 && let Some(roots) = form.get(b"Fields", work)?
219 {
220 let members = roots.members(work).ok_or(Error {
221 kind: ErrorKind::Syntax(Syntax::Dictionary),
222 location: roots.direct().location(),
223 })?;
224 for root in members {
225 let object = root?.resolved(work)?.ok_or(Error {
226 kind: ErrorKind::Syntax(Syntax::Dictionary),
227 location,
228 })?;
229 pending
230 .try_push(Pending {
231 object,
232 parent: None,
233 signature: false,
234 })
235 .map_err(|cause| Error {
236 kind: ErrorKind::Resource(cause),
237 location,
238 })?;
239 }
240 }
241 Ok(())
242}
243
244impl<'s, S: RangeSource> Document<'s, S> {
245 async fn field_name<'g, W: Work>(
246 &self,
247 graph: &'g Graph<'s, S::Document, S::Generation>,
248 object: GraphObject<'g, 's, S::Document, S::Generation>,
249 parent_name: Option<&str>,
250 work: &W,
251 ) -> Result<OwnedText<W>, ReadFailure<S::Error>> {
252 let location = object.direct().location();
253 let mut name = if let Some(parent) = parent_name {
254 OwnedText::try_from_str(parent, work).map_err(|cause| Error {
255 kind: ErrorKind::Resource(cause),
256 location,
257 })?
258 } else {
259 OwnedText::try_from_str("", work).map_err(|cause| Error {
260 kind: ErrorKind::Resource(cause),
261 location,
262 })?
263 };
264 if let Some(part) = object.get(b"T", work)? {
265 let reading = graph.nodes[part.owner]
266 .reading
267 .as_ref()
268 .expect("resolved field text owner");
269 let bytes = self
270 .string_in(
271 reading,
272 graph.decoded(part.owner),
273 part.node,
274 usize::MAX,
275 work,
276 )
277 .await?;
278 let text = crate::text::read(&bytes, part.direct().location(), work)?;
279 admit(work, part.direct().location(), text.len() as u64)?;
280 if text.as_bytes().contains(&b'.') || text.is_empty() {
281 return Err(Error {
282 kind: ErrorKind::Syntax(Syntax::String),
283 location: part.direct().location(),
284 }
285 .into());
286 }
287 if !name.is_empty() {
288 name.try_push_str(".").map_err(|cause| Error {
289 kind: ErrorKind::Resource(cause),
290 location,
291 })?;
292 }
293 name.try_push_str(text.as_str()).map_err(|cause| Error {
294 kind: ErrorKind::Resource(cause),
295 location,
296 })?;
297 }
298 Ok(name)
299 }
300
301 async fn read_field<'g, W: Work>(
302 &self,
303 graph: &'g Graph<'s, S::Document, S::Generation>,
304 item: &Pending<'g, 's, S::Document, S::Generation>,
305 values: &[Field<'g, 's, S::Document, S::Generation>],
306 work: &W,
307 ) -> Result<Option<Field<'g, 's, S::Document, S::Generation>>, ReadFailure<S::Error>> {
308 let object = item.object;
309 let parent = item.parent;
310 let inherited_signature = item.signature;
311 let location = object.direct().location();
312 if object.direct().kind() != crate::object::Type::Dictionary {
313 return Err(Error {
314 kind: ErrorKind::Syntax(Syntax::Dictionary),
315 location,
316 }
317 .into());
318 }
319 if let Some(parent) = parent {
320 let backlink = object.get(b"Parent", work)?.ok_or(Error {
321 kind: ErrorKind::Syntax(Syntax::Dictionary),
322 location,
323 })?;
324 let expected = values[parent].object;
325 if backlink.direct().location() != expected.direct().location() {
326 return Err(Error {
327 kind: ErrorKind::Ambiguous(Syntax::Dictionary),
328 location,
329 }
330 .into());
331 }
332 }
333 let signature = match object.get(b"FT", work)? {
334 Some(kind) => kind.direct().name_equals(b"Sig", work)?,
335 None => inherited_signature,
336 };
337 let name = self
338 .field_name(
339 graph,
340 object,
341 parent.map(|ordinal| values[ordinal].name()),
342 work,
343 )
344 .await?;
345 let widget = object
347 .get(b"Subtype", work)?
348 .map(|value| value.direct().name_equals(b"Widget", work))
349 .transpose()?
350 .unwrap_or(false);
351 if widget && object.get(b"T", work)?.is_none() && object.get(b"FT", work)?.is_none() {
352 return Ok(None);
353 }
354 Ok(Some(Field {
355 object,
356 name: name.into_owned(),
357 signature,
358 parent,
359 }))
360 }
361
362 pub async fn fields<'g, W: Work>(
368 &self,
369 graph: &'g Graph<'s, S::Document, S::Generation>,
370 operation: &W,
371 ) -> Result<Fields<'g, 's, S::Document, S::Generation>, ReadFailure<S::Error>> {
372 let work = self.session.query(operation);
373 let location = graph.root().direct().location();
374 if !core::ptr::eq(graph.session, self.session) || graph.stamp != self.stamp {
375 return Err(Error {
376 kind: ErrorKind::Foreign,
377 location,
378 }
379 .into());
380 }
381 self.check(&work, location)?;
382 let mut values: OwnedVec<Field<'g, 's, S::Document, S::Generation>, _> = work.vector();
383 let mut pending = work.vector();
384 let mut seen = work.map();
385 seed(graph, &mut pending, location, &work)?;
386 let mut at = 0;
387 while at < pending.len() {
388 admit(&work, location, 1)?;
389 let object = pending[at].object;
390 let location = object.direct().location();
391 let position = Position {
392 owner: object.owner,
393 node: object.node.0,
394 };
395 if seen
396 .try_insert(position, ())
397 .map_err(|cause| Error {
398 kind: ErrorKind::Resource(cause),
399 location,
400 })?
401 .is_some()
402 {
403 return Err(Error {
404 kind: ErrorKind::Ambiguous(Syntax::Cycle),
405 location,
406 }
407 .into());
408 }
409 let Some(field) = self.read_field(graph, &pending[at], &values, &work).await? else {
410 at += 1;
411 continue;
412 };
413 let signature = field.signature;
414 let ordinal = values.len();
415 if let Some(kids) = object.get(b"Kids", &work)? {
416 let members = kids.members(&work).ok_or(Error {
417 kind: ErrorKind::Syntax(Syntax::Dictionary),
418 location: kids.direct().location(),
419 })?;
420 for child in members {
421 let child = child?.resolved(&work)?.ok_or(Error {
422 kind: ErrorKind::Syntax(Syntax::Dictionary),
423 location,
424 })?;
425 pending
426 .try_push(Pending {
427 object: child,
428 parent: Some(ordinal),
429 signature,
430 })
431 .map_err(|cause| Error {
432 kind: ErrorKind::Resource(cause),
433 location,
434 })?;
435 }
436 }
437 values.try_push(field).map_err(|cause| Error {
438 kind: ErrorKind::Resource(cause),
439 location,
440 })?;
441 at += 1;
442 }
443 let ordered = ordered(&values, location, &work)?;
444 self.check(&work, location)?;
445 Ok(Fields {
446 graph,
447 values: values.into_owned(),
448 index: ordered.into_owned(),
449 })
450 }
451}