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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
//! # (`hcim`) The hardcopy images

use std::borrow::Cow;

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

use crate::{
    images::imc::{decode_imc, MonochromeScreen},
    util::{Buf, Bytes16, Bytes32},
};

use super::{bytes16, bytes32};

#[derive(Debug)]
/// The header of a HCIM chunk
pub struct HCIMHeader {
    /// The length of the site_table
    pub header_length: u32,
    /// The number of images stored as bitmaps
    pub img_count: u16,
    /// The number of image use-sites within the document
    pub site_count: u16,
    /// Unknown, probably padding
    pub c: Bytes32,
    /// Unknown, probably padding
    pub d: Bytes32,
}

#[derive(Debug)]
#[allow(non_snake_case)]
/// Information on an image site
///
/// This struct defines what part of an image is used at which position in the document
pub struct ImageSite {
    /// The index of the page that has this image
    pub page: u16,
    /// The site of the image
    pub site: ImageArea,
    /// Unknown
    pub _5: u16,
    /// The selection of the original image that is displayed
    pub sel: ImageArea,
    /// Unknown
    pub _A: u16,
    /// Unknown
    pub _B: u16,
    /// Unknown
    pub _C: u16,
    /// The index of the image that is used
    pub img: u16,
    /// Unknown
    pub _E: u16,
    /// Unknown
    pub _F: Bytes16,
}

#[derive(Debug, Copy, Clone)]
/// The area of an image
pub struct ImageArea {
    /// The horizontal position of the left edge
    pub x: u16,
    /// The vertical position of the top edge
    pub y: u16,
    /// The horizontal dimension / width
    pub w: u16,
    /// The vertical dimension / height
    pub h: u16,
}

#[derive(Debug)]
/// A partiall parsed HCIM
pub struct HCIM<'a> {
    /// The header
    pub header: HCIMHeader,
    /// The table of sites
    pub sites: Vec<ImageSite>,
    /// The table of images
    pub images: Vec<Buf<'a>>,
}

/// Parse an entry in the images table
pub fn parse_image_buf(input: &[u8]) -> IResult<&[u8], Buf> {
    let (input, length2) = be_u32(input)?;
    let (input, buf2) = take((length2 - 4) as usize)(input)?;
    Ok((input, Buf(buf2)))
}

#[derive(Debug)]
/// A parsed image
pub struct Image<'a> {
    /// The filename
    pub key: Cow<'a, str>,
    /// The (padding?) bytes after the name
    pub bytes: Buf<'a>,
    /// The uncompressed image
    pub image: MonochromeScreen,
}

const ZERO: &[u8] = &[0];

/// Parse an embedded image file
pub fn parse_image(input: &[u8]) -> IResult<&[u8], Image> {
    let (input, key_bytes) = take_until(ZERO)(input)?;
    let key = String::from_utf8_lossy(key_bytes);

    let (input, _) = tag(ZERO)(input)?;
    let (input, bytes) = take(27usize - key_bytes.len())(input)?;
    let (input, image) = decode_imc(input)?;

    let bytes = Buf(bytes);
    Ok((input, Image { key, bytes, image }))
}

/// Parse the `hcim` header
pub fn parse_hcim_header(input: &[u8]) -> IResult<&[u8], HCIMHeader> {
    let (input, header_length) = be_u32(input)?;
    let (input, img_count) = be_u16(input)?;
    let (input, site_count) = be_u16(input)?;
    let (input, c) = bytes32(input)?;
    let (input, d) = bytes32(input)?;

    Ok((
        input,
        HCIMHeader {
            header_length,
            img_count,
            site_count,
            c,
            d,
        },
    ))
}

#[allow(non_snake_case, clippy::just_underscores_and_digits)]
/// Parse a site table entry
pub fn parse_hcim_img_ref(input: &[u8]) -> IResult<&[u8], ImageSite> {
    let (input, page) = be_u16(input)?;
    let (input, site_x) = be_u16(input)?;
    let (input, site_y) = be_u16(input)?;
    let (input, site_w) = be_u16(input)?;
    let (input, site_h) = be_u16(input)?;
    let (input, _5) = be_u16(input)?;
    let (input, sel_x) = be_u16(input)?;
    let (input, sel_y) = be_u16(input)?;
    let (input, sel_w) = be_u16(input)?;
    let (input, sel_h) = be_u16(input)?;
    let (input, _A) = be_u16(input)?;
    let (input, _B) = be_u16(input)?;
    let (input, _C) = be_u16(input)?;
    let (input, img) = be_u16(input)?;
    let (input, _E) = be_u16(input)?;
    let (input, _F) = bytes16(input)?;
    Ok((
        input,
        ImageSite {
            page,
            site: ImageArea {
                x: site_x,
                y: site_y,
                w: site_w,
                h: site_h,
            },
            _5,
            sel: ImageArea {
                x: sel_x,
                y: sel_y,
                w: sel_w,
                h: sel_h,
            },
            _A,
            _B,
            _C,
            img,
            _E,
            _F,
        },
    ))
}

/// Parse a `hcim` chunk
pub fn parse_hcim(input: &[u8]) -> IResult<&[u8], HCIM> {
    let (input, header) = parse_hcim_header(input)?;
    let (input, buf) = take(header.header_length as usize)(input)?;
    let (_, sites) = count(parse_hcim_img_ref, header.site_count as usize)(buf)?;
    let (input, images) = count(parse_image_buf, header.img_count as usize)(input)?;

    Ok((
        input,
        HCIM {
            header,
            sites,
            images,
        },
    ))
}