1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! # (`pbuf`) The page buffer

use nom::{
    bytes::{complete::tag, streaming::take},
    number::complete::{be_u16, be_u32},
    IResult,
};

use crate::util::{Buf, Bytes16};

use super::bytes16;

#[derive(Debug)]
/// The page buffer
pub struct PBuf<'a> {
    /// The total number of pages
    pub page_count: u32,
    /// The length of the entry for each page
    pub kl: u32,
    /// The logical number for the first page
    pub first_page_nr: u32,
    /// A sparse map of pages, ordered by their index
    pub pages: Vec<Option<(Page, Buf<'a>)>>,
}

#[derive(Debug)]
/// The margins of a page
pub struct Margin {
    /// Width of the left margin
    pub left: u16,
    /// Distance of the right text margin from the left edge of the paper
    pub right: u16,
    /// Height of the header
    pub top: u16,
    /// Height of the footer
    pub bottom: u16,
}

#[derive(Debug)]
/// Structure representing a single page
pub struct Page {
    /// Page number over all documents from the same collection
    pub phys_pnr: u16,
    /// Page number within the current file / document
    pub log_pnr: u16,

    /// The total number of lines (?)
    pub lines: u16,
    /// The margins of this page
    pub margin: Margin,
    /// Specifies the position of the page number
    pub numbpos: Bytes16,
    /// May specify the current chapter (?)
    pub kapitel: Bytes16,
    /// Unknown
    pub intern: Bytes16,
}

fn parse_margin(input: &[u8]) -> IResult<&[u8], Margin> {
    let (input, left) = be_u16(input)?;
    let (input, right) = be_u16(input)?;
    let (input, top) = be_u16(input)?;
    let (input, bottom) = be_u16(input)?;

    Ok((
        input,
        Margin {
            left,
            right,
            top,
            bottom,
        },
    ))
}

fn parse_page(input: &[u8]) -> IResult<&[u8], (Page, Buf)> {
    let (input, phys_pnr) = be_u16(input)?;
    let (input, log_pnr) = be_u16(input)?;

    let (input, lines) = be_u16(input)?;
    let (input, margin) = parse_margin(input)?;
    let (input, numbpos) = bytes16(input)?;
    let (input, kapitel) = bytes16(input)?;
    let (input, intern) = bytes16(input)?;

    let (input, rest) = take(12usize)(input)?;
    Ok((
        input,
        (
            Page {
                phys_pnr,
                log_pnr,

                lines,

                margin,
                numbpos,
                kapitel,
                intern,
            },
            Buf(rest),
        ),
    ))
}

/// Parse a `pbuf` chunk
pub fn parse_pbuf(input: &[u8]) -> IResult<&[u8], PBuf> {
    let (input, page_count) = be_u32(input)?;
    let (input, kl) = be_u32(input)?;
    let (input, first_page_nr) = be_u32(input)?;
    let (input, _) = tag(b"unde")(input)?;
    let (input, _) = tag(b"unde")(input)?;
    let (input, _) = tag(b"unde")(input)?;
    let (input, _) = tag(b"unde")(input)?;
    let (input, _) = tag(b"unde")(input)?;

    let mut pages = Vec::with_capacity(page_count as usize);
    let mut rest = input;

    for _ in 0..page_count {
        let (input, index) = be_u16(rest)?;
        let (input, (page, buf)) = parse_page(input)?;
        rest = input;
        let uindex = index as usize;
        if let Some(entry) = pages.get_mut(uindex) {
            *entry = Some((page, buf))
        } else {
            while pages.len() < uindex {
                pages.push(None);
            }
            pages.push(Some((page, buf)));
        }
    }

    Ok((
        rest,
        PBuf {
            page_count,
            kl,
            first_page_nr,
            pages,
        },
    ))
}