use bitflags::bitflags;
use nom::{
combinator::{iterator, map_parser, map_res},
error::ErrorKind,
multi::{length_data, many0},
number::complete::{be_u16, be_u32},
sequence::tuple,
IResult,
};
use super::bytes16;
#[derive(Debug, Copy, Clone)]
pub struct Style {
pub underlined: bool,
pub footnote: bool,
pub sth1: bool,
pub bold: bool,
pub italic: bool,
pub sth2: bool,
pub small: bool,
}
impl Default for Style {
fn default() -> Self {
Style {
underlined: false,
footnote: false,
sth1: false,
bold: false,
italic: false,
sth2: false,
small: false,
}
}
}
#[derive(Debug, Copy, Clone)]
pub struct Char {
pub cval: u8,
pub cset: u8,
pub offset: u16,
pub style: Style,
}
#[derive(Debug)]
pub struct TextBufferHeader {
pub lines_total: u32,
}
pub fn parse_tebu_header(input: &[u8]) -> IResult<&[u8], TextBufferHeader> {
let (input, lines_total) = be_u32(input)?;
Ok((
input,
TextBufferHeader {
lines_total,
},
))
}
#[derive(Debug)]
pub struct TeBu<'a> {
pub header: TextBufferHeader,
pub lines: Vec<LineBuf<'a>>,
}
#[derive(Clone)]
pub struct LineIter<'a> {
rest: &'a [u8],
}
impl<'a> LineIter<'a> {
pub fn as_slice(&self) -> &'a [u8] {
self.rest
}
}
impl<'a> Iterator for LineIter<'a> {
type Item = Result<LineBuf<'a>, nom::Err<nom::error::Error<&'a [u8]>>>;
fn next(&mut self) -> Option<Self::Item> {
if self.rest.len() <= 4 {
None
} else {
match parse_line_buf(self.rest) {
Ok((rest, buf)) => {
self.rest = rest;
Some(Ok(buf))
}
Err(e) => Some(Err(e)),
}
}
}
}
fn te(input: &[u8]) -> IResult<&[u8], Char> {
let (input, cmd) = be_u16(input)?;
let val = (cmd & 0x7E00) >> 9;
let cset = ((cmd & 0x0180) >> 7) as u8;
let cval = (cmd & 0x007F) as u8;
if cmd >= 0x8000 {
Ok((
input,
Char {
cval,
cset,
offset: val,
style: Style::default(),
},
))
} else {
let (input, extra) = be_u16(input)?;
let offset = extra & 0x07ff;
let underlined = val & 0x20 > 0;
let footnote = val & 0x02 > 0;
let cset = cset | (((val & 0x01) as u8) << 2);
let sth1 = extra & 0x8000 > 0;
let bold = extra & 0x4000 > 0;
let italic = extra & 0x2000 > 0;
let sth2 = extra & 0x1000 > 0;
let small = extra & 0x0800 > 0;
Ok((
input,
Char {
cval,
cset,
offset,
style: Style {
underlined,
footnote,
sth1,
bold,
italic,
sth2,
small,
},
},
))
}
}
#[derive(Debug, Copy, Clone)]
pub struct LineBuf<'a> {
pub skip: u16,
pub data: &'a [u8],
}
bitflags! {
pub struct Flags: u16 {
const FLAG = 0x0001;
const PNUM = 0x0080;
const LINE = 0x0400;
const PARA = 0x0800;
const ALIG = 0x1000;
const PEND = 0x2000;
const PNEW = 0x4000;
const PAGE = 0x8000;
}
}
#[derive(Debug)]
pub struct Line {
pub flags: Flags,
pub extra: u16,
pub data: Vec<Char>,
}
pub fn parse_line(input: &[u8]) -> IResult<&[u8], Line> {
let (input, bits) = bytes16(input)?;
let flags = Flags::from_bits(bits.0).expect("Unknown flags");
if flags.contains(Flags::PAGE) {
let (input, pnum) = if flags.contains(Flags::PNUM) {
be_u16(input)?
} else {
(input, 0)
};
Ok((
input,
Line {
flags,
extra: pnum,
data: vec![],
},
))
} else {
let (input, extra) = if flags.contains(Flags::FLAG) {
be_u16(input)?
} else {
(input, 0)
};
let (input, text) = many0(te)(input)?;
Ok((
input,
Line {
flags,
extra,
data: text,
},
))
}
}
impl<'a> LineBuf<'a> {
pub fn parse(self) -> Result<Line, nom::Err<nom::error::Error<&'a [u8]>>> {
parse_line(self.data).map(|(_, line)| line)
}
}
fn parse_line_buf(input: &[u8]) -> IResult<&[u8], LineBuf> {
let (input, skip) = be_u16(input)?;
let (input, data) = length_data(be_u16)(input)?;
Ok((input, LineBuf { skip, data }))
}
fn parse_buffered_line(input: &[u8]) -> IResult<&[u8], (u16, Line)> {
tuple((be_u16, map_parser(length_data(be_u16), parse_line)))(input)
}
fn parse_page_start_line(input: &[u8]) -> IResult<&[u8], (u16, u16)> {
map_res(parse_buffered_line, |(a, l)| {
if l.flags.contains(Flags::PAGE & Flags::PNEW) {
Ok((a, l.extra))
} else {
Err("Expected the start of a page!")
}
})(input)
}
pub struct PageText {
pub index: u16,
pub skip: u16,
pub rskip: u16,
pub content: Vec<(u16, Line)>,
}
pub fn parse_page_text(input: &[u8]) -> IResult<&[u8], PageText> {
let (input, (lskip, index)) = parse_page_start_line(input)?;
let mut iter = iterator(input, parse_buffered_line);
let mut content = vec![];
for (skip, line) in &mut iter {
if !line.flags.contains(Flags::PAGE) {
content.push((skip, line));
continue;
}
if !line.flags.contains(Flags::PEND) {
panic!("This is an unknown case, please send in this document for investigation.")
}
assert_eq!(line.extra, index);
return iter.finish().map(|(rest, ())| {
let text = PageText {
index,
skip: lskip,
rskip: skip,
content,
};
(rest, text)
});
}
match iter.finish() {
Ok((rest, ())) => Err(nom::Err::Failure(nom::error::Error {
input: rest,
code: ErrorKind::Eof,
})),
Err(e) => Err(e),
}
}
pub fn parse_tebu(input: &[u8]) -> IResult<&[u8], TeBu> {
let (input, header) = parse_tebu_header(input)?;
let (input, lines) = many0(parse_line_buf)(input)?;
Ok((input, TeBu { header, lines }))
}