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
use bitflags::bitflags;
use nom::{combinator::cond, multi::count};

use crate::binary::{
    errors::ParseResult,
    scalars::{dword, long, parse_dword_as_usize, parse_string, Dword, Long},
};

#[derive(Debug)]
pub struct SliceChunk<'a> {
    pub name: &'a str,
    pub flags: SliceFlags,
    pub slice_keys: Vec<SliceKey>,
}

bitflags! {
    #[derive(Debug, Copy, Clone)]
    pub struct SliceFlags: Dword {
        const NINE_PATCH = 0x01;
        const PIVOT = 0x02;
    }
}

#[derive(Debug, Copy, Clone)]
pub struct SliceKey {
    pub frame_number: Dword,
    pub x: Long,
    pub y: Long,
    pub width: Dword,
    pub height: Dword,
    pub nine_patch: Option<NinePatch>,
    pub pivot: Option<Pivot>,
}

#[derive(Debug, Copy, Clone)]
pub struct NinePatch {
    pub x: Long,
    pub y: Long,
    pub width: Dword,
    pub height: Dword,
}

#[derive(Debug, Copy, Clone)]
pub struct Pivot {
    pub x: Long,
    pub y: Long,
}

pub fn parse_slice_chunk(input: &[u8]) -> ParseResult<'_, SliceChunk<'_>> {
    let (input, number_of_keys) = parse_dword_as_usize(input)?;
    let (input, flags) = dword(input)?;
    let flags = SliceFlags::from_bits_truncate(flags);
    let (input, _) = dword(input)?;
    let (input, name) = parse_string(input)?;
    let (input, slice_keys) = count(|input| parse_slice_key(input, flags), number_of_keys)(input)?;
    Ok((
        input,
        SliceChunk {
            name,
            flags,
            slice_keys,
        },
    ))
}

pub fn parse_slice_key(input: &[u8], flags: SliceFlags) -> ParseResult<'_, SliceKey> {
    let (input, frame_number) = dword(input)?;
    let (input, x) = long(input)?;
    let (input, y) = long(input)?;
    let (input, width) = dword(input)?;
    let (input, height) = dword(input)?;
    let (input, nine_patch) =
        cond(flags.contains(SliceFlags::NINE_PATCH), parse_nine_patch)(input)?;
    let (input, pivot) = cond(flags.contains(SliceFlags::PIVOT), parse_pivot)(input)?;
    Ok((
        input,
        SliceKey {
            frame_number,
            x,
            y,
            width,
            height,
            nine_patch,
            pivot,
        },
    ))
}

pub fn parse_nine_patch(input: &[u8]) -> ParseResult<'_, NinePatch> {
    let (input, x) = long(input)?;
    let (input, y) = long(input)?;
    let (input, width) = dword(input)?;
    let (input, height) = dword(input)?;
    Ok((
        input,
        NinePatch {
            x,
            y,
            width,
            height,
        },
    ))
}

pub fn parse_pivot(input: &[u8]) -> ParseResult<'_, Pivot> {
    let (input, x) = long(input)?;
    let (input, y) = long(input)?;
    Ok((input, Pivot { x, y }))
}