1use super::{Document, Reading};
4use crate::arena::{Arena, Kind};
5use crate::error::{Error, ErrorKind, ReadFailure, Syntax};
6use crate::model::{admit, get, named, required, unsigned};
7use crate::object::Value;
8use crate::range::RangeSource;
9use crate::signature::{Catalogue, inspect, inspect_part};
10use crate::syntax::{Cursor, read_into};
11use crate::xref::Target;
12use structured_asn1::memory::{OwnedVec, SortError, Work};
13
14struct Census<'a, 's, D, G, W: Work> {
15 readings: &'a mut OwnedVec<Reading<'s, D, G>, W>,
16 signatures: &'a mut OwnedVec<crate::signature::Entry, W>,
17 failures: &'a mut OwnedVec<crate::signature::Failure, W>,
18 order: &'a mut OwnedVec<crate::signature::Position, W>,
19 definitions: &'a mut OwnedVec<crate::signature::Definition, W>,
20}
21
22#[derive(Clone, Copy)]
23struct Physical {
24 start: u64,
25 revision: usize,
26 xref_stream: bool,
27}
28
29struct Scan<'a> {
30 table: Option<&'a super::Section>,
31 revision: Option<usize>,
32 ignored_footer: Option<u64>,
33 xref_stream: bool,
34}
35
36struct Expected {
37 offset: u64,
38 number: u64,
39 generation: u16,
40 member: Option<(u64, u64)>,
41 location: crate::source::Location,
42 found: bool,
43}
44
45impl<S: RangeSource> Document<'_, S> {
46 fn expected<W: Work>(&self, work: &W) -> crate::Result<OwnedVec<Expected, W>> {
47 let mut expected = work.vector();
48 for entry in &self.entries {
49 admit(work, entry.location, 1)?;
50 let generation = match entry.target {
51 Target::File { generation, .. } => generation,
52 Target::Compressed { .. } => 0,
53 _ => continue,
54 };
55 if self.target(entry.revision, entry.number, generation, work)? != Some(entry.target) {
56 continue;
57 }
58 let (offset, number, generation, member) = match entry.target {
59 Target::File { offset, generation } => (offset, entry.number, generation, None),
60 Target::Compressed { stream, index } => {
61 let Some(Target::File {
62 offset,
63 generation: 0,
64 }) = self.target(entry.revision, stream, 0, work)?
65 else {
66 return Err(Error {
67 kind: ErrorKind::Syntax(Syntax::CrossReference),
68 location: entry.location,
69 });
70 };
71 (offset, stream, 0, Some((index, entry.number)))
72 }
73 _ => unreachable!("only selected file/compressed rows"),
74 };
75 expected
76 .try_push(Expected {
77 offset,
78 number,
79 generation,
80 member,
81 location: entry.location,
82 found: false,
83 })
84 .map_err(|cause| Error {
85 kind: ErrorKind::Resource(cause),
86 location: entry.location,
87 })?;
88 }
89 expected
90 .try_sort_unstable_by(|a, b| {
91 admit(work, b.location, 1)?;
92 Ok::<_, Error>(a.offset.cmp(&b.offset))
93 })
94 .map_err(|cause| match cause {
95 SortError::Comparison(cause) => cause,
96 SortError::Resource(cause) => Error {
97 kind: ErrorKind::Resource(cause),
98 location: self.arena.nodes[self.history[0].trailer.0].location,
99 },
100 })?;
101 Ok(expected)
102 }
103}
104
105fn first_at(expected: &[Expected], offset: u64, work: &impl Work) -> crate::Result<usize> {
106 let mut low = 0;
107 let mut high = expected.len();
108 while low < high {
109 let middle = low + (high - low) / 2;
110 admit(work, expected[middle].location, 1)?;
111 if expected[middle].offset < offset {
112 low = middle + 1;
113 } else {
114 high = middle;
115 }
116 }
117 Ok(low)
118}
119
120fn check_expected(
121 expected: &mut [Expected],
122 identity: (u64, u16),
123 members: Option<&[super::members::Member]>,
124 start: u64,
125 work: &impl Work,
126) -> crate::Result<()> {
127 let mut entry = first_at(expected, start, work)?;
128 while entry < expected.len() {
129 admit(work, expected[entry].location, 1)?;
130 if expected[entry].offset != start {
131 break;
132 }
133 let item = &mut expected[entry];
134 if item.number != identity.0 || item.generation != identity.1 {
135 return Err(Error {
136 kind: ErrorKind::Syntax(Syntax::CrossReference),
137 location: item.location,
138 });
139 }
140 if let Some((index, number)) = item.member {
141 let index = usize::try_from(index).map_err(|_| Error {
142 kind: ErrorKind::Syntax(Syntax::CrossReference),
143 location: item.location,
144 })?;
145 if members.is_none_or(|members| {
146 members
147 .get(index)
148 .is_none_or(|member| member.number != number)
149 }) {
150 return Err(Error {
151 kind: ErrorKind::Syntax(Syntax::CrossReference),
152 location: item.location,
153 });
154 }
155 }
156 item.found = true;
157 entry += 1;
158 }
159 Ok(())
160}
161
162impl<'s, S: RangeSource> Document<'s, S> {
163 async fn physical_reading(
164 &self,
165 cursor: &mut Cursor<'_, S>,
166 revision: usize,
167 work: &impl Work,
168 ) -> Result<Reading<'s, S::Document, S::Generation>, ReadFailure<S::Error>> {
169 let start = cursor.at;
170 let (arena, indirect) = crate::stream::open(cursor, Arena::new(work).into_owned()).await?;
171 let mut stream = None;
172 if let Some(body) = indirect.stream {
173 let length = required(&arena, indirect.value, b"Length", work)?;
174 let length = match arena.nodes[length.0].kind {
175 Kind::Reference { number, generation } => {
176 let value = self
177 .object(revision, number, generation, work)
178 .await?
179 .ok_or_else(|| cursor.failure(Syntax::Stream, body))?;
180 value.value.root().unsigned(work)?
181 }
182 _ => unsigned(&arena, length, work)?,
183 };
184 stream = Some(crate::stream::close(cursor, body, length).await?);
185 }
186 if cursor.at > self.history[revision].facts.end {
187 return Err(cursor.failure(Syntax::Object, start));
188 }
189 let reading = Reading {
190 value: Value {
191 arena,
192 root: indirect.value,
193 session: self.session,
194 stamp: self.stamp,
195 end: cursor.at,
196 },
197 decoded: None,
198 stream,
199 number: indirect.number,
200 generation: indirect.generation,
201 revision,
202 };
203 Ok(reading)
204 }
205
206 fn inspect_members<W: Work>(
207 &self,
208 group: Reading<'s, S::Document, S::Generation>,
209 members: &[super::members::Member],
210 location: crate::source::Location,
211 census: Census<'_, 's, S::Document, S::Generation, W>,
212 work: &impl Work,
213 ) -> crate::Result<()> {
214 let Census {
215 readings,
216 signatures,
217 failures,
218 order,
219 definitions,
220 } = census;
221 let revision = group.revision;
222 let before = order.len();
223 for member in members {
224 admit(work, location, 1)?;
225 let location = group.value.arena.nodes[member.root.0].location;
226 definitions
227 .try_push(crate::signature::Definition {
228 identity: (member.number, 0),
229 location,
230 encoded: location,
231 revision,
232 kind: crate::signature::DefinitionKind::Object,
233 })
234 .map_err(|cause| Error {
235 kind: ErrorKind::Resource(cause),
236 location,
237 })?;
238 inspect_part(
239 self,
240 &group,
241 readings.len(),
242 member.nodes.clone(),
243 (member.number, 0),
244 crate::signature::Inspection {
245 entries: signatures,
246 failures,
247 order,
248 },
249 work,
250 )?;
251 }
252 if order.len() != before {
253 readings.try_push(group).map_err(|cause| Error {
254 kind: ErrorKind::Resource(cause),
255 location,
256 })?;
257 }
258 Ok(())
259 }
260
261 async fn census_object<W: Work>(
262 &self,
263 cursor: &mut Cursor<'_, S>,
264 point: Physical,
265 census: Census<'_, 's, S::Document, S::Generation, W>,
266 expected: &mut [Expected],
267 work: &impl Work,
268 ) -> Result<(), ReadFailure<S::Error>> {
269 let Physical {
270 start,
271 revision,
272 xref_stream,
273 } = point;
274 let Census {
275 readings,
276 signatures,
277 failures,
278 order,
279 definitions,
280 } = census;
281 let reading = self.physical_reading(cursor, revision, work).await?;
282 let mut object_stream = false;
283 if reading.stream.is_some()
284 && let Some(kind) = get(&reading.value.arena, reading.value.root, b"Type", work)?
285 {
286 object_stream = if let Kind::Reference { number, generation } =
287 reading.value.arena.nodes[kind.0].kind
288 {
289 let kind = self.object(revision, number, generation, work).await?;
290 if let Some(kind) = kind {
291 kind.value.root().name_equals(b"ObjStm", work)?
292 } else {
293 false
294 }
295 } else {
296 named(&reading.value.arena, kind, b"ObjStm", work)?
297 };
298 }
299 let members = if object_stream {
300 self.all_members(&reading, work).await?
301 } else {
302 None
303 };
304 definitions
305 .try_push(crate::signature::Definition {
306 identity: (reading.number, reading.generation),
307 location: reading.value.root().location(),
308 encoded: cursor.location(start, cursor.at - start),
309 revision,
310 kind: if xref_stream {
311 crate::signature::DefinitionKind::CrossReference
312 } else if object_stream {
313 crate::signature::DefinitionKind::ObjectStream
314 } else {
315 crate::signature::DefinitionKind::Object
316 },
317 })
318 .map_err(|cause| Error {
319 kind: ErrorKind::Resource(cause),
320 location: cursor.location(start, 0),
321 })?;
322 check_expected(
323 expected,
324 (reading.number, reading.generation),
325 members.as_ref().map(|(_, values)| &values[..]),
326 start,
327 work,
328 )?;
329 let before = order.len();
330 inspect(
331 self,
332 &reading,
333 readings.len(),
334 signatures,
335 failures,
336 order,
337 work,
338 )?;
339 if order.len() != before {
340 readings.try_push(reading).map_err(|cause| Error {
341 kind: ErrorKind::Resource(cause),
342 location: cursor.location(start, 0),
343 })?;
344 }
345 if let Some((group, members)) = members {
346 self.inspect_members(
347 group,
348 &members,
349 cursor.location(start, 0),
350 Census {
351 readings,
352 signatures,
353 failures,
354 order,
355 definitions,
356 },
357 work,
358 )?;
359 }
360 Ok(())
361 }
362
363 fn scan_point(
364 &self,
365 start: u64,
366 location: crate::source::Location,
367 seen: &mut [bool],
368 work: &impl Work,
369 ) -> crate::Result<Scan<'_>> {
370 let mut table = None;
371 let mut revision = None;
372 let mut ignored_footer = None;
373 let mut xref_stream = false;
374 for (ordinal, section) in self.sections.iter().enumerate() {
375 admit(work, location, 1)?;
376 if section.offset == start {
377 seen[ordinal] = true;
378 if section.table {
379 table = Some(section);
380 } else {
381 xref_stream = true;
382 }
383 }
384 if let Some((at, end)) = section.ignored_footer
385 && at == start
386 {
387 ignored_footer = Some(end);
388 }
389 }
390 for (ordinal, historical) in self.history.iter().enumerate() {
391 admit(work, location, 1)?;
392 if revision.is_none() && start < historical.facts.end {
393 revision = Some(ordinal);
394 }
395 }
396 Ok(Scan {
397 table,
398 revision,
399 ignored_footer,
400 xref_stream,
401 })
402 }
403
404 async fn census_trailer<W: Work>(
405 &self,
406 cursor: &mut Cursor<'_, S>,
407 section: &super::Section,
408 revision: Option<usize>,
409 start: u64,
410 census: Census<'_, 's, S::Document, S::Generation, W>,
411 work: &impl Work,
412 ) -> Result<(), ReadFailure<S::Error>> {
413 let Census {
414 readings,
415 signatures,
416 failures,
417 order,
418 definitions: _,
419 } = census;
420 cursor.at = section.trailer.span().start;
421 let (arena, root) = read_into(cursor, self.session, Arena::new(work).into_owned()).await?;
422 if cursor.at != section.end {
423 return Err(cursor.failure(Syntax::CrossReference, cursor.at));
424 }
425 let reading = Reading {
426 value: Value {
427 arena,
428 root,
429 session: self.session,
430 stamp: self.stamp,
431 end: cursor.at,
432 },
433 decoded: None,
434 stream: None,
435 number: 0,
436 generation: 0,
437 revision: revision.ok_or_else(|| cursor.failure(Syntax::Trailer, start))?,
438 };
439 let before = order.len();
440 inspect(
441 self,
442 &reading,
443 readings.len(),
444 signatures,
445 failures,
446 order,
447 work,
448 )?;
449 if order.len() != before {
450 readings.try_push(reading).map_err(|cause| Error {
451 kind: ErrorKind::Resource(cause),
452 location: cursor.location(start, 0),
453 })?;
454 }
455 Ok(())
456 }
457
458 fn check_census(
459 &self,
460 cursor: &Cursor<'_, S>,
461 seen: &[bool],
462 expected: &[Expected],
463 work: &impl Work,
464 ) -> Result<(), ReadFailure<S::Error>> {
465 for (ordinal, &encountered) in seen.iter().enumerate() {
466 admit(work, cursor.location(self.sections[ordinal].offset, 0), 1)?;
467 if !encountered {
468 return Err(cursor.failure(Syntax::CrossReference, self.sections[ordinal].offset));
469 }
470 }
471 for item in expected {
472 admit(work, item.location, 1)?;
473 if !item.found {
474 return Err(Error {
475 kind: ErrorKind::Syntax(Syntax::CrossReference),
476 location: item.location,
477 }
478 .into());
479 }
480 }
481 Ok(())
482 }
483
484 pub async fn catalogue<W: Work>(
489 &self,
490 operation: &W,
491 ) -> Result<Catalogue<'s, S::Document, S::Generation>, ReadFailure<S::Error>> {
492 let reader = self.original_reader(operation)?;
493 let work = reader.execution();
494 let mut cursor = Cursor { reader, at: 0 };
495 let mut readings = work.vector();
496 let mut signatures = work.vector();
497 let mut failures = work.vector();
498 let mut order = work.vector();
499 let mut definitions = work.vector();
500 let mut expected = self.expected(&work)?;
501 let mut seen = work.vector();
502 for _ in &self.sections {
503 seen.try_push(false).map_err(|cause| Error {
504 kind: ErrorKind::Resource(cause),
505 location: cursor.location(0, 0),
506 })?;
507 }
508 while cursor.at < self.stamp.length {
509 cursor.skip().await?;
510 if cursor.peek().await?.is_none() {
511 break;
512 }
513 let start = cursor.at;
514 let Scan {
515 table,
516 revision,
517 ignored_footer,
518 xref_stream,
519 } = self.scan_point(start, cursor.location(start, 0), &mut seen, &work)?;
520 if let Some(end) = ignored_footer {
521 cursor.at = end;
522 continue;
523 }
524 if let Some(section) = table {
525 self.census_trailer(
526 &mut cursor,
527 section,
528 revision,
529 start,
530 Census {
531 readings: &mut readings,
532 signatures: &mut signatures,
533 failures: &mut failures,
534 order: &mut order,
535 definitions: &mut definitions,
536 },
537 &work,
538 )
539 .await?;
540 continue;
541 }
542 if cursor.looking(b"startxref").await? {
543 cursor.keyword(b"startxref").await?;
544 cursor.space().await?;
545 let offset = cursor.natural().await?;
546 let end = super::finish_footer(&mut cursor).await?;
547 let mut found = false;
548 for historical in &self.history {
549 admit(&work, cursor.location(start, 0), 1)?;
550 if historical.facts.xref == offset && historical.facts.end == end {
551 found = true;
552 break;
553 }
554 }
555 if !found {
556 return Err(cursor.failure(Syntax::StartXref, start));
557 }
558 continue;
559 }
560 let revision = revision.ok_or_else(|| cursor.failure(Syntax::Object, start))?;
561 self.census_object(
562 &mut cursor,
563 Physical {
564 start,
565 revision,
566 xref_stream,
567 },
568 Census {
569 readings: &mut readings,
570 signatures: &mut signatures,
571 failures: &mut failures,
572 order: &mut order,
573 definitions: &mut definitions,
574 },
575 &mut expected,
576 &work,
577 )
578 .await?;
579 }
580 self.check_census(&cursor, &seen, &expected, &work)?;
581 cursor.reader.check(cursor.location(0, self.stamp.length))?;
582 Ok(Catalogue {
583 readings: readings.into_owned(),
584 entries: signatures.into_owned(),
585 failures: failures.into_owned(),
586 order: order.into_owned(),
587 definitions: definitions.into_owned(),
588 })
589 }
590}