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
use bitflags::bitflags;
use nom::{
    bytes::complete::take,
    combinator::{flat_map, map},
};
use strum::FromRepr;

use crate::binary::{
    errors::ParseResult,
    scalars::{dword, fixed, word, Fixed, Word},
};

#[derive(Debug)]
pub struct ColorProfileChunk<'a> {
    pub fixed_gamma: Option<Fixed>,
    pub profile: ColorProfile<'a>,
}

#[derive(Debug, Copy, Clone, FromRepr)]
pub enum ColorProfileType {
    NoColorProfile,
    Srgb,
    EmbeddedICC,
    Unknown(Word),
}

bitflags! {
    pub struct ColorProfileFlags: Word {
        const FIXED_GAMMA = 0x01;
    }
}

#[derive(Debug)]
pub enum ColorProfile<'a> {
    NoColorProfile,
    Srgb,
    EmbeddedICC(&'a [u8]),
    Unknown(Word),
}

pub fn parse_color_profile(input: &[u8]) -> ParseResult<'_, ColorProfileChunk<'_>> {
    let (input, profile_type) = word(input)?;
    let profile_type = ColorProfileType::from_repr(profile_type.into())
        .unwrap_or(ColorProfileType::Unknown(profile_type));
    let (input, flags) = word(input)?;
    let flags = ColorProfileFlags::from_bits_truncate(flags);
    let (input, fixed_gamma) = fixed(input)?;
    let (input, _) = take(8usize)(input)?;
    let (input, profile) = match profile_type {
        ColorProfileType::NoColorProfile => (input, ColorProfile::NoColorProfile),
        ColorProfileType::Srgb => (input, ColorProfile::Srgb),
        ColorProfileType::EmbeddedICC => {
            map(flat_map(dword, take), ColorProfile::EmbeddedICC)(input)?
        }
        ColorProfileType::Unknown(word) => (input, ColorProfile::Unknown(word)),
    };
    Ok((
        input,
        ColorProfileChunk {
            fixed_gamma: if flags.contains(ColorProfileFlags::FIXED_GAMMA) {
                Some(fixed_gamma)
            } else {
                None
            },
            profile,
        },
    ))
}