Compressed Macintosh resource data, Apple `'dcmp' (1)` format: Rust parsing library

Compressed resource data in 'dcmp' (1) format, as stored in compressed resources with header type 8 and decompressor ID 1.

The 'dcmp' (1) decompressor resource is included in the System file of System 7.0 and later. This compression format is used for a few compressed resources in System 7.0's files (such as the Finder Help file). This decompressor is also included with and used by some other Apple applications, such as ResEdit. (Note: ResEdit includes the 'dcmp' (1) resource, but none of its resources actually use this decompressor.)

This compression format supports some basic general-purpose compression schemes, including backreferences to previous data and run-length encoding. It also includes some types of compression tailored specifically to Mac OS resources, including a set of single-byte codes that correspond to entries in a hard-coded lookup table.

The 'dcmp' (0) compression format (see dcmp_0.ksy) is very similar to this format, with the main difference that it operates mostly on units of 2 or 4 bytes. This makes the ``dcmp' (0)format more suitable for word-aligned data, such as executable code, bitmaps, sounds, etc. The'dcmp' (0)` format also appears to be generally preferred over `'dcmp' (1)`, with the latter only being used in resource files that contain mostly unaligned data, such as text.

Application

Mac OS

KS implementation details

License: MIT
Minimal Kaitai Struct required: 0.8

This page hosts a formal specification of Compressed Macintosh resource data, Apple `'dcmp' (1)` format using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Rust source code to parse Compressed Macintosh resource data, Apple `'dcmp' (1)` format

dcmp_1.rs

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

#![allow(unused_imports)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(irrefutable_let_patterns)]
#![allow(unused_comparisons)]

extern crate kaitai;
use kaitai::*;
use std::convert::{TryFrom, TryInto};
use std::cell::{Ref, Cell, RefCell};
use std::rc::{Rc, Weak};
use super::dcmp_variable_length_integer::DcmpVariableLengthInteger;

/**
 * Compressed resource data in `'dcmp' (1)` format,
 * as stored in compressed resources with header type `8` and decompressor ID `1`.
 * 
 * The `'dcmp' (1)` decompressor resource is included in the System file of System 7.0 and later.
 * This compression format is used for a few compressed resources in System 7.0's files
 * (such as the Finder Help file).
 * This decompressor is also included with and used by some other Apple applications,
 * such as ResEdit.
 * (Note: ResEdit includes the `'dcmp' (1)` resource,
 * but none of its resources actually use this decompressor.)
 * 
 * This compression format supports some basic general-purpose compression schemes,
 * including backreferences to previous data and run-length encoding.
 * It also includes some types of compression tailored specifically to Mac OS resources,
 * including a set of single-byte codes that correspond to entries in a hard-coded lookup table.
 * 
 * The `'dcmp' (0)` compression format (see dcmp_0.ksy) is very similar to this format,
 * with the main difference that it operates mostly on units of 2 or 4 bytes.
 * This makes the ``dcmp' (0)` format more suitable for word-aligned data,
 * such as executable code, bitmaps, sounds, etc.
 * The `'dcmp' (0)` format also appears to be generally preferred over `'dcmp' (1)`,
 * with the latter only being used in resource files that contain mostly unaligned data,
 * such as text.
 * \sa https://github.com/dgelessus/python-rsrcfork/blob/f891a6e/src/rsrcfork/compress/dcmp1.py Source
 */

#[derive(Default, Debug, Clone)]
pub struct Dcmp1 {
    pub _root: SharedType<Dcmp1>,
    pub _parent: SharedType<Dcmp1>,
    pub _self: SharedType<Self>,
    chunks: RefCell<Vec<OptRc<Dcmp1_Chunk>>>,
    _io: RefCell<BytesReader>,
}
impl KStruct for Dcmp1 {
    type Root = Dcmp1;
    type Parent = Dcmp1;

    fn read<S: KStream>(
        self_rc: &OptRc<Self>,
        _io: &S,
        _root: SharedType<Self::Root>,
        _parent: SharedType<Self::Parent>,
    ) -> KResult<()> {
        *self_rc._io.borrow_mut() = _io.clone();
        self_rc._root.set(_root.get());
        self_rc._parent.set(_parent.get());
        self_rc._self.set(Ok(self_rc.clone()));
        let _rrc = self_rc._root.get_value().borrow().upgrade();
        let _prc = self_rc._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        *self_rc.chunks.borrow_mut() = Vec::new();
        {
            let mut _i = 0;
            while {
                let t = Self::read_into::<_, Dcmp1_Chunk>(&*_io, Some(self_rc._root.clone()), Some(self_rc._self.clone()))?.into();
                self_rc.chunks.borrow_mut().push(t);
                let _t_chunks = self_rc.chunks.borrow();
                let _tmpa = _t_chunks.last().unwrap();
                _i += 1;
                let x = !(*_tmpa.tag() == 255);
                x
            } {}
        }
        Ok(())
    }
}
impl Dcmp1 {
}

/**
 * The sequence of chunks that make up the compressed data.
 */
impl Dcmp1 {
    pub fn chunks(&self) -> Ref<'_, Vec<OptRc<Dcmp1_Chunk>>> {
        self.chunks.borrow()
    }
}
impl Dcmp1 {
    pub fn _io(&self) -> Ref<'_, BytesReader> {
        self._io.borrow()
    }
}

/**
 * A single chunk of compressed data.
 * Each chunk in the compressed data expands to a sequence of bytes in the uncompressed data,
 * except when `tag == 0xff`,
 * which marks the end of the data and does not correspond to any bytes in the uncompressed data.
 * 
 * Most chunks are stateless and always expand to the same data,
 * regardless of where the chunk appears in the sequence.
 * However,
 * some chunks affect the behavior of future chunks,
 * or expand to different data depending on which chunks came before them.
 */

#[derive(Default, Debug, Clone)]
pub struct Dcmp1_Chunk {
    pub _root: SharedType<Dcmp1>,
    pub _parent: SharedType<Dcmp1>,
    pub _self: SharedType<Self>,
    tag: RefCell<u8>,
    body: RefCell<Option<Dcmp1_Chunk_Body>>,
    _io: RefCell<BytesReader>,
}
#[derive(Debug, Clone)]
pub enum Dcmp1_Chunk_Body {
    Dcmp1_Chunk_EndBody(OptRc<Dcmp1_Chunk_EndBody>),
    Dcmp1_Chunk_ExtendedBody(OptRc<Dcmp1_Chunk_ExtendedBody>),
    Dcmp1_Chunk_TableLookupBody(OptRc<Dcmp1_Chunk_TableLookupBody>),
    Dcmp1_Chunk_BackreferenceBody(OptRc<Dcmp1_Chunk_BackreferenceBody>),
    Dcmp1_Chunk_LiteralBody(OptRc<Dcmp1_Chunk_LiteralBody>),
}
impl From<&Dcmp1_Chunk_Body> for OptRc<Dcmp1_Chunk_EndBody> {
    fn from(v: &Dcmp1_Chunk_Body) -> Self {
        if let Dcmp1_Chunk_Body::Dcmp1_Chunk_EndBody(x) = v {
            return x.clone();
        }
        panic!("expected Dcmp1_Chunk_Body::Dcmp1_Chunk_EndBody, got {:?}", v)
    }
}
impl From<OptRc<Dcmp1_Chunk_EndBody>> for Dcmp1_Chunk_Body {
    fn from(v: OptRc<Dcmp1_Chunk_EndBody>) -> Self {
        Self::Dcmp1_Chunk_EndBody(v)
    }
}
impl From<&Dcmp1_Chunk_Body> for OptRc<Dcmp1_Chunk_ExtendedBody> {
    fn from(v: &Dcmp1_Chunk_Body) -> Self {
        if let Dcmp1_Chunk_Body::Dcmp1_Chunk_ExtendedBody(x) = v {
            return x.clone();
        }
        panic!("expected Dcmp1_Chunk_Body::Dcmp1_Chunk_ExtendedBody, got {:?}", v)
    }
}
impl From<OptRc<Dcmp1_Chunk_ExtendedBody>> for Dcmp1_Chunk_Body {
    fn from(v: OptRc<Dcmp1_Chunk_ExtendedBody>) -> Self {
        Self::Dcmp1_Chunk_ExtendedBody(v)
    }
}
impl From<&Dcmp1_Chunk_Body> for OptRc<Dcmp1_Chunk_TableLookupBody> {
    fn from(v: &Dcmp1_Chunk_Body) -> Self {
        if let Dcmp1_Chunk_Body::Dcmp1_Chunk_TableLookupBody(x) = v {
            return x.clone();
        }
        panic!("expected Dcmp1_Chunk_Body::Dcmp1_Chunk_TableLookupBody, got {:?}", v)
    }
}
impl From<OptRc<Dcmp1_Chunk_TableLookupBody>> for Dcmp1_Chunk_Body {
    fn from(v: OptRc<Dcmp1_Chunk_TableLookupBody>) -> Self {
        Self::Dcmp1_Chunk_TableLookupBody(v)
    }
}
impl From<&Dcmp1_Chunk_Body> for OptRc<Dcmp1_Chunk_BackreferenceBody> {
    fn from(v: &Dcmp1_Chunk_Body) -> Self {
        if let Dcmp1_Chunk_Body::Dcmp1_Chunk_BackreferenceBody(x) = v {
            return x.clone();
        }
        panic!("expected Dcmp1_Chunk_Body::Dcmp1_Chunk_BackreferenceBody, got {:?}", v)
    }
}
impl From<OptRc<Dcmp1_Chunk_BackreferenceBody>> for Dcmp1_Chunk_Body {
    fn from(v: OptRc<Dcmp1_Chunk_BackreferenceBody>) -> Self {
        Self::Dcmp1_Chunk_BackreferenceBody(v)
    }
}
impl From<&Dcmp1_Chunk_Body> for OptRc<Dcmp1_Chunk_LiteralBody> {
    fn from(v: &Dcmp1_Chunk_Body) -> Self {
        if let Dcmp1_Chunk_Body::Dcmp1_Chunk_LiteralBody(x) = v {
            return x.clone();
        }
        panic!("expected Dcmp1_Chunk_Body::Dcmp1_Chunk_LiteralBody, got {:?}", v)
    }
}
impl From<OptRc<Dcmp1_Chunk_LiteralBody>> for Dcmp1_Chunk_Body {
    fn from(v: OptRc<Dcmp1_Chunk_LiteralBody>) -> Self {
        Self::Dcmp1_Chunk_LiteralBody(v)
    }
}
impl KStruct for Dcmp1_Chunk {
    type Root = Dcmp1;
    type Parent = Dcmp1;

    fn read<S: KStream>(
        self_rc: &OptRc<Self>,
        _io: &S,
        _root: SharedType<Self::Root>,
        _parent: SharedType<Self::Parent>,
    ) -> KResult<()> {
        *self_rc._io.borrow_mut() = _io.clone();
        self_rc._root.set(_root.get());
        self_rc._parent.set(_parent.get());
        self_rc._self.set(Ok(self_rc.clone()));
        let _rrc = self_rc._root.get_value().borrow().upgrade();
        let _prc = self_rc._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        *self_rc.tag.borrow_mut() = _io.read_u1()?.into();
        match if  ((((*self_rc.tag() as u8) >= (0 as u8))) && (((*self_rc.tag() as u8) <= (31 as u8))))  { Dcmp1_Chunk_TagKind::Literal.clone() } else { if  ((((*self_rc.tag() as u8) >= (32 as u8))) && (*self_rc.tag() <= 207))  { Dcmp1_Chunk_TagKind::Backreference.clone() } else { if  ((*self_rc.tag() >= 208) && (*self_rc.tag() <= 209))  { Dcmp1_Chunk_TagKind::Literal.clone() } else { if *self_rc.tag() == 210 { Dcmp1_Chunk_TagKind::Backreference.clone() } else { if  ((*self_rc.tag() >= 213) && (*self_rc.tag() <= 253))  { Dcmp1_Chunk_TagKind::TableLookup.clone() } else { if *self_rc.tag() == 254 { Dcmp1_Chunk_TagKind::Extended.clone() } else { if *self_rc.tag() == 255 { Dcmp1_Chunk_TagKind::End.clone() } else { Dcmp1_Chunk_TagKind::Invalid.clone() }.clone() }.clone() }.clone() }.clone() }.clone() }.clone() } {
            Dcmp1_Chunk_TagKind::Backreference => {
                let f = |t : &mut Dcmp1_Chunk_BackreferenceBody| Ok(t.set_params((*self_rc.tag()).try_into().map_err(|_| KError::CastError)?));
                let t = Self::read_into_with_init::<_, Dcmp1_Chunk_BackreferenceBody>(&*_io, Some(self_rc._root.clone()), Some(self_rc._self.clone()), &f)?.into();
                *self_rc.body.borrow_mut() = Some(t);
            }
            Dcmp1_Chunk_TagKind::End => {
                let t = Self::read_into::<_, Dcmp1_Chunk_EndBody>(&*_io, Some(self_rc._root.clone()), Some(self_rc._self.clone()))?.into();
                *self_rc.body.borrow_mut() = Some(t);
            }
            Dcmp1_Chunk_TagKind::Extended => {
                let t = Self::read_into::<_, Dcmp1_Chunk_ExtendedBody>(&*_io, Some(self_rc._root.clone()), Some(self_rc._self.clone()))?.into();
                *self_rc.body.borrow_mut() = Some(t);
            }
            Dcmp1_Chunk_TagKind::Literal => {
                let f = |t : &mut Dcmp1_Chunk_LiteralBody| Ok(t.set_params((*self_rc.tag()).try_into().map_err(|_| KError::CastError)?));
                let t = Self::read_into_with_init::<_, Dcmp1_Chunk_LiteralBody>(&*_io, Some(self_rc._root.clone()), Some(self_rc._self.clone()), &f)?.into();
                *self_rc.body.borrow_mut() = Some(t);
            }
            Dcmp1_Chunk_TagKind::TableLookup => {
                let f = |t : &mut Dcmp1_Chunk_TableLookupBody| Ok(t.set_params((*self_rc.tag()).try_into().map_err(|_| KError::CastError)?));
                let t = Self::read_into_with_init::<_, Dcmp1_Chunk_TableLookupBody>(&*_io, Some(self_rc._root.clone()), Some(self_rc._self.clone()), &f)?.into();
                *self_rc.body.borrow_mut() = Some(t);
            }
            _ => {}
        }
        Ok(())
    }
}
impl Dcmp1_Chunk {
}

/**
 * The chunk's tag byte.
 * This controls the structure of the body and the meaning of the chunk.
 */
impl Dcmp1_Chunk {
    pub fn tag(&self) -> Ref<'_, u8> {
        self.tag.borrow()
    }
}

/**
 * The chunk's body.
 * 
 * Certain chunks do not have any data following the tag byte.
 * In this case,
 * the body is a zero-length structure.
 */
impl Dcmp1_Chunk {
    pub fn body(&self) -> Ref<'_, Option<Dcmp1_Chunk_Body>> {
        self.body.borrow()
    }
}
impl Dcmp1_Chunk {
    pub fn _io(&self) -> Ref<'_, BytesReader> {
        self._io.borrow()
    }
}
#[derive(Debug, PartialEq, Clone)]
pub enum Dcmp1_Chunk_TagKind {
    Invalid,
    Literal,
    Backreference,
    TableLookup,
    Extended,
    End,
    Unknown(i64),
}

impl TryFrom<i64> for Dcmp1_Chunk_TagKind {
    type Error = KError;
    fn try_from(flag: i64) -> KResult<Dcmp1_Chunk_TagKind> {
        match flag {
            -1 => Ok(Dcmp1_Chunk_TagKind::Invalid),
            0 => Ok(Dcmp1_Chunk_TagKind::Literal),
            1 => Ok(Dcmp1_Chunk_TagKind::Backreference),
            2 => Ok(Dcmp1_Chunk_TagKind::TableLookup),
            3 => Ok(Dcmp1_Chunk_TagKind::Extended),
            4 => Ok(Dcmp1_Chunk_TagKind::End),
            _ => Ok(Dcmp1_Chunk_TagKind::Unknown(flag)),
        }
    }
}

impl From<&Dcmp1_Chunk_TagKind> for i64 {
    fn from(v: &Dcmp1_Chunk_TagKind) -> Self {
        match *v {
            Dcmp1_Chunk_TagKind::Invalid => -1,
            Dcmp1_Chunk_TagKind::Literal => 0,
            Dcmp1_Chunk_TagKind::Backreference => 1,
            Dcmp1_Chunk_TagKind::TableLookup => 2,
            Dcmp1_Chunk_TagKind::Extended => 3,
            Dcmp1_Chunk_TagKind::End => 4,
            Dcmp1_Chunk_TagKind::Unknown(v) => v
        }
    }
}

impl Default for Dcmp1_Chunk_TagKind {
    fn default() -> Self { Dcmp1_Chunk_TagKind::Unknown(0) }
}


/**
 * The body of a backreference chunk.
 * 
 * This chunk expands to the data stored in a preceding literal chunk,
 * indicated by an index number (`index`).
 */

#[derive(Default, Debug, Clone)]
pub struct Dcmp1_Chunk_BackreferenceBody {
    pub _root: SharedType<Dcmp1>,
    pub _parent: SharedType<Dcmp1_Chunk>,
    pub _self: SharedType<Self>,
    tag: RefCell<u8>,
    index_separate_minus: RefCell<u8>,
    _io: RefCell<BytesReader>,
    f_index: Cell<bool>,
    index: RefCell<i32>,
    f_index_in_tag: Cell<bool>,
    index_in_tag: RefCell<i32>,
    f_index_separate: Cell<bool>,
    index_separate: RefCell<i32>,
    f_is_index_separate: Cell<bool>,
    is_index_separate: RefCell<bool>,
}
impl KStruct for Dcmp1_Chunk_BackreferenceBody {
    type Root = Dcmp1;
    type Parent = Dcmp1_Chunk;

    fn read<S: KStream>(
        self_rc: &OptRc<Self>,
        _io: &S,
        _root: SharedType<Self::Root>,
        _parent: SharedType<Self::Parent>,
    ) -> KResult<()> {
        *self_rc._io.borrow_mut() = _io.clone();
        self_rc._root.set(_root.get());
        self_rc._parent.set(_parent.get());
        self_rc._self.set(Ok(self_rc.clone()));
        let _rrc = self_rc._root.get_value().borrow().upgrade();
        let _prc = self_rc._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        if *self_rc.is_index_separate()? {
            *self_rc.index_separate_minus.borrow_mut() = _io.read_u1()?.into();
        }
        Ok(())
    }
}
impl Dcmp1_Chunk_BackreferenceBody {
    pub fn tag(&self) -> Ref<'_, u8> {
        self.tag.borrow()
    }
}
impl Dcmp1_Chunk_BackreferenceBody {
    pub fn set_params(&mut self, tag: u8) {
        *self.tag.borrow_mut() = tag;
    }
}
impl Dcmp1_Chunk_BackreferenceBody {

    /**
     * The index of the referenced literal chunk.
     * 
     * Stored literals are assigned index numbers in the order in which they appear in the compressed data,
     * starting at 0.
     * Non-stored literals are not counted in the numbering and cannot be referenced using backreferences.
     * Once an index is assigned to a stored literal,
     * it is never changed or unassigned for the entire length of the compressed data.
     * 
     * As the name indicates,
     * a backreference can only reference stored literal chunks found *before* the backreference,
     * not ones that come after it.
     */
    pub fn index(
        &self
    ) -> KResult<Ref<'_, i32>> {
        let _io = self._io.borrow();
        let _rrc = self._root.get_value().borrow().upgrade();
        let _prc = self._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        if self.f_index.get() {
            return Ok(self.index.borrow());
        }
        self.f_index.set(true);
        *self.index.borrow_mut() = (if *self.is_index_separate()? { *self.index_separate()? } else { *self.index_in_tag()? }) as i32;
        Ok(self.index.borrow())
    }

    /**
     * The index of the referenced literal chunk,
     * as stored in the tag byte.
     */
    pub fn index_in_tag(
        &self
    ) -> KResult<Ref<'_, i32>> {
        let _io = self._io.borrow();
        let _rrc = self._root.get_value().borrow().upgrade();
        let _prc = self._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        if self.f_index_in_tag.get() {
            return Ok(self.index_in_tag.borrow());
        }
        self.f_index_in_tag.set(true);
        *self.index_in_tag.borrow_mut() = (((*self.tag() as u8) - (32 as u8))) as i32;
        Ok(self.index_in_tag.borrow())
    }

    /**
     * The index of the referenced literal chunk,
     * as stored separately from the tag byte,
     * with the implicit offset corrected for.
     */
    pub fn index_separate(
        &self
    ) -> KResult<Ref<'_, i32>> {
        let _io = self._io.borrow();
        let _rrc = self._root.get_value().borrow().upgrade();
        let _prc = self._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        if self.f_index_separate.get() {
            return Ok(self.index_separate.borrow());
        }
        self.f_index_separate.set(true);
        if *self.is_index_separate()? {
            *self.index_separate.borrow_mut() = (((*self.index_separate_minus() as u8) + (176 as u8))) as i32;
        }
        Ok(self.index_separate.borrow())
    }

    /**
     * Whether the index is stored separately from the tag.
     */
    pub fn is_index_separate(
        &self
    ) -> KResult<Ref<'_, bool>> {
        let _io = self._io.borrow();
        let _rrc = self._root.get_value().borrow().upgrade();
        let _prc = self._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        if self.f_is_index_separate.get() {
            return Ok(self.is_index_separate.borrow());
        }
        self.f_is_index_separate.set(true);
        *self.is_index_separate.borrow_mut() = (*self.tag() == 210) as bool;
        Ok(self.is_index_separate.borrow())
    }
}

/**
 * The index of the referenced literal chunk,
 * stored separately from the tag.
 * The value in this field is stored minus 0xb0.
 * 
 * This field is only present if the tag byte is 0xd2.
 * For other tag bytes,
 * the index is encoded in the tag byte.
 * Values smaller than 0xb0 cannot be stored in this field,
 * they must always be encoded in the tag byte.
 */
impl Dcmp1_Chunk_BackreferenceBody {
    pub fn index_separate_minus(&self) -> Ref<'_, u8> {
        self.index_separate_minus.borrow()
    }
}
impl Dcmp1_Chunk_BackreferenceBody {
    pub fn _io(&self) -> Ref<'_, BytesReader> {
        self._io.borrow()
    }
}

/**
 * The body of an end chunk.
 * This body is always empty.
 * 
 * The last chunk in the compressed data must always be an end chunk.
 * An end chunk cannot appear elsewhere in the compressed data.
 */

#[derive(Default, Debug, Clone)]
pub struct Dcmp1_Chunk_EndBody {
    pub _root: SharedType<Dcmp1>,
    pub _parent: SharedType<Dcmp1_Chunk>,
    pub _self: SharedType<Self>,
    _io: RefCell<BytesReader>,
}
impl KStruct for Dcmp1_Chunk_EndBody {
    type Root = Dcmp1;
    type Parent = Dcmp1_Chunk;

    fn read<S: KStream>(
        self_rc: &OptRc<Self>,
        _io: &S,
        _root: SharedType<Self::Root>,
        _parent: SharedType<Self::Parent>,
    ) -> KResult<()> {
        *self_rc._io.borrow_mut() = _io.clone();
        self_rc._root.set(_root.get());
        self_rc._parent.set(_parent.get());
        self_rc._self.set(Ok(self_rc.clone()));
        let _rrc = self_rc._root.get_value().borrow().upgrade();
        let _prc = self_rc._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        Ok(())
    }
}
impl Dcmp1_Chunk_EndBody {
}
impl Dcmp1_Chunk_EndBody {
    pub fn _io(&self) -> Ref<'_, BytesReader> {
        self._io.borrow()
    }
}

/**
 * The body of an extended chunk.
 * The meaning of this chunk depends on the extended tag byte stored in the chunk data.
 */

#[derive(Default, Debug, Clone)]
pub struct Dcmp1_Chunk_ExtendedBody {
    pub _root: SharedType<Dcmp1>,
    pub _parent: SharedType<Dcmp1_Chunk>,
    pub _self: SharedType<Self>,
    tag: RefCell<u8>,
    body: RefCell<Option<Dcmp1_Chunk_ExtendedBody_Body>>,
    _io: RefCell<BytesReader>,
}
#[derive(Debug, Clone)]
pub enum Dcmp1_Chunk_ExtendedBody_Body {
    Dcmp1_Chunk_ExtendedBody_RepeatBody(OptRc<Dcmp1_Chunk_ExtendedBody_RepeatBody>),
}
impl From<&Dcmp1_Chunk_ExtendedBody_Body> for OptRc<Dcmp1_Chunk_ExtendedBody_RepeatBody> {
    fn from(v: &Dcmp1_Chunk_ExtendedBody_Body) -> Self {
        if let Dcmp1_Chunk_ExtendedBody_Body::Dcmp1_Chunk_ExtendedBody_RepeatBody(x) = v {
            return x.clone();
        }
        panic!("expected Dcmp1_Chunk_ExtendedBody_Body::Dcmp1_Chunk_ExtendedBody_RepeatBody, got {:?}", v)
    }
}
impl From<OptRc<Dcmp1_Chunk_ExtendedBody_RepeatBody>> for Dcmp1_Chunk_ExtendedBody_Body {
    fn from(v: OptRc<Dcmp1_Chunk_ExtendedBody_RepeatBody>) -> Self {
        Self::Dcmp1_Chunk_ExtendedBody_RepeatBody(v)
    }
}
impl Dcmp1_Chunk_ExtendedBody_Body {
    pub fn to_repeat_raw(&self) -> OptRc<DcmpVariableLengthInteger> {
        match self {
            Dcmp1_Chunk_ExtendedBody_Body::Dcmp1_Chunk_ExtendedBody_RepeatBody(x) => x.to_repeat_raw.borrow().clone(),
        }
    }
}
impl Dcmp1_Chunk_ExtendedBody_Body {
    pub fn repeat_count_m1_raw(&self) -> OptRc<DcmpVariableLengthInteger> {
        match self {
            Dcmp1_Chunk_ExtendedBody_Body::Dcmp1_Chunk_ExtendedBody_RepeatBody(x) => x.repeat_count_m1_raw.borrow().clone(),
        }
    }
}
impl KStruct for Dcmp1_Chunk_ExtendedBody {
    type Root = Dcmp1;
    type Parent = Dcmp1_Chunk;

    fn read<S: KStream>(
        self_rc: &OptRc<Self>,
        _io: &S,
        _root: SharedType<Self::Root>,
        _parent: SharedType<Self::Parent>,
    ) -> KResult<()> {
        *self_rc._io.borrow_mut() = _io.clone();
        self_rc._root.set(_root.get());
        self_rc._parent.set(_parent.get());
        self_rc._self.set(Ok(self_rc.clone()));
        let _rrc = self_rc._root.get_value().borrow().upgrade();
        let _prc = self_rc._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        *self_rc.tag.borrow_mut() = _io.read_u1()?.into();
        match *self_rc.tag() {
            2 => {
                let t = Self::read_into::<_, Dcmp1_Chunk_ExtendedBody_RepeatBody>(&*_io, Some(self_rc._root.clone()), Some(self_rc._self.clone()))?.into();
                *self_rc.body.borrow_mut() = Some(t);
            }
            _ => {}
        }
        Ok(())
    }
}
impl Dcmp1_Chunk_ExtendedBody {
}

/**
 * The chunk's extended tag byte.
 * This controls the structure of the body and the meaning of the chunk.
 */
impl Dcmp1_Chunk_ExtendedBody {
    pub fn tag(&self) -> Ref<'_, u8> {
        self.tag.borrow()
    }
}

/**
 * The chunk's body.
 */
impl Dcmp1_Chunk_ExtendedBody {
    pub fn body(&self) -> Ref<'_, Option<Dcmp1_Chunk_ExtendedBody_Body>> {
        self.body.borrow()
    }
}
impl Dcmp1_Chunk_ExtendedBody {
    pub fn _io(&self) -> Ref<'_, BytesReader> {
        self._io.borrow()
    }
}

/**
 * The body of a repeat chunk.
 * 
 * This chunk expands to the same byte repeated a number of times,
 * i. e. it implements a form of run-length encoding.
 */

#[derive(Default, Debug, Clone)]
pub struct Dcmp1_Chunk_ExtendedBody_RepeatBody {
    pub _root: SharedType<Dcmp1>,
    pub _parent: SharedType<Dcmp1_Chunk_ExtendedBody>,
    pub _self: SharedType<Self>,
    to_repeat_raw: RefCell<OptRc<DcmpVariableLengthInteger>>,
    repeat_count_m1_raw: RefCell<OptRc<DcmpVariableLengthInteger>>,
    _io: RefCell<BytesReader>,
    f_repeat_count: Cell<bool>,
    repeat_count: RefCell<i32>,
    f_repeat_count_m1: Cell<bool>,
    repeat_count_m1: RefCell<i32>,
    f_to_repeat: Cell<bool>,
    to_repeat: RefCell<i32>,
}
impl KStruct for Dcmp1_Chunk_ExtendedBody_RepeatBody {
    type Root = Dcmp1;
    type Parent = Dcmp1_Chunk_ExtendedBody;

    fn read<S: KStream>(
        self_rc: &OptRc<Self>,
        _io: &S,
        _root: SharedType<Self::Root>,
        _parent: SharedType<Self::Parent>,
    ) -> KResult<()> {
        *self_rc._io.borrow_mut() = _io.clone();
        self_rc._root.set(_root.get());
        self_rc._parent.set(_parent.get());
        self_rc._self.set(Ok(self_rc.clone()));
        let _rrc = self_rc._root.get_value().borrow().upgrade();
        let _prc = self_rc._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        let t = Self::read_into::<_, DcmpVariableLengthInteger>(&*_io, None, None)?.into();
        *self_rc.to_repeat_raw.borrow_mut() = t;
        let t = Self::read_into::<_, DcmpVariableLengthInteger>(&*_io, None, None)?.into();
        *self_rc.repeat_count_m1_raw.borrow_mut() = t;
        Ok(())
    }
}
impl Dcmp1_Chunk_ExtendedBody_RepeatBody {

    /**
     * The number of times to repeat the value.
     * 
     * This value must be positive.
     */
    pub fn repeat_count(
        &self
    ) -> KResult<Ref<'_, i32>> {
        let _io = self._io.borrow();
        let _rrc = self._root.get_value().borrow().upgrade();
        let _prc = self._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        if self.f_repeat_count.get() {
            return Ok(self.repeat_count.borrow());
        }
        self.f_repeat_count.set(true);
        *self.repeat_count.borrow_mut() = (((*self.repeat_count_m1()? as i32) + (1 as i32))) as i32;
        Ok(self.repeat_count.borrow())
    }

    /**
     * The number of times to repeat the value,
     * minus one.
     * 
     * This value must not be negative.
     */
    pub fn repeat_count_m1(
        &self
    ) -> KResult<Ref<'_, i32>> {
        let _io = self._io.borrow();
        let _rrc = self._root.get_value().borrow().upgrade();
        let _prc = self._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        if self.f_repeat_count_m1.get() {
            return Ok(self.repeat_count_m1.borrow());
        }
        self.f_repeat_count_m1.set(true);
        *self.repeat_count_m1.borrow_mut() = (*self.repeat_count_m1_raw().value()?) as i32;
        Ok(self.repeat_count_m1.borrow())
    }

    /**
     * The value to repeat.
     * 
     * Although it is stored as a variable-length integer,
     * this value must fit into an unsigned 8-bit integer.
     */
    pub fn to_repeat(
        &self
    ) -> KResult<Ref<'_, i32>> {
        let _io = self._io.borrow();
        let _rrc = self._root.get_value().borrow().upgrade();
        let _prc = self._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        if self.f_to_repeat.get() {
            return Ok(self.to_repeat.borrow());
        }
        self.f_to_repeat.set(true);
        *self.to_repeat.borrow_mut() = (*self.to_repeat_raw().value()?) as i32;
        Ok(self.to_repeat.borrow())
    }
}

/**
 * Raw variable-length integer representation of `to_repeat`.
 */
impl Dcmp1_Chunk_ExtendedBody_RepeatBody {
    pub fn to_repeat_raw(&self) -> Ref<'_, OptRc<DcmpVariableLengthInteger>> {
        self.to_repeat_raw.borrow()
    }
}

/**
 * Raw variable-length integer representation of `repeat_count_m1`.
 */
impl Dcmp1_Chunk_ExtendedBody_RepeatBody {
    pub fn repeat_count_m1_raw(&self) -> Ref<'_, OptRc<DcmpVariableLengthInteger>> {
        self.repeat_count_m1_raw.borrow()
    }
}
impl Dcmp1_Chunk_ExtendedBody_RepeatBody {
    pub fn _io(&self) -> Ref<'_, BytesReader> {
        self._io.borrow()
    }
}

/**
 * The body of a literal data chunk.
 * 
 * The data that this chunk expands to is stored literally in the body (`literal`).
 * Optionally,
 * the literal data may also be stored for use by future backreference chunks (`do_store`).
 */

#[derive(Default, Debug, Clone)]
pub struct Dcmp1_Chunk_LiteralBody {
    pub _root: SharedType<Dcmp1>,
    pub _parent: SharedType<Dcmp1_Chunk>,
    pub _self: SharedType<Self>,
    tag: RefCell<u8>,
    len_literal_separate: RefCell<u8>,
    literal: RefCell<Vec<u8>>,
    _io: RefCell<BytesReader>,
    f_do_store: Cell<bool>,
    do_store: RefCell<bool>,
    f_is_len_literal_separate: Cell<bool>,
    is_len_literal_separate: RefCell<bool>,
    f_len_literal: Cell<bool>,
    len_literal: RefCell<i32>,
    f_len_literal_m1_in_tag: Cell<bool>,
    len_literal_m1_in_tag: RefCell<i32>,
}
impl KStruct for Dcmp1_Chunk_LiteralBody {
    type Root = Dcmp1;
    type Parent = Dcmp1_Chunk;

    fn read<S: KStream>(
        self_rc: &OptRc<Self>,
        _io: &S,
        _root: SharedType<Self::Root>,
        _parent: SharedType<Self::Parent>,
    ) -> KResult<()> {
        *self_rc._io.borrow_mut() = _io.clone();
        self_rc._root.set(_root.get());
        self_rc._parent.set(_parent.get());
        self_rc._self.set(Ok(self_rc.clone()));
        let _rrc = self_rc._root.get_value().borrow().upgrade();
        let _prc = self_rc._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        if *self_rc.is_len_literal_separate()? {
            *self_rc.len_literal_separate.borrow_mut() = _io.read_u1()?.into();
        }
        *self_rc.literal.borrow_mut() = _io.read_bytes(*self_rc.len_literal()? as usize)?.into();
        Ok(())
    }
}
impl Dcmp1_Chunk_LiteralBody {
    pub fn tag(&self) -> Ref<'_, u8> {
        self.tag.borrow()
    }
}
impl Dcmp1_Chunk_LiteralBody {
    pub fn set_params(&mut self, tag: u8) {
        *self.tag.borrow_mut() = tag;
    }
}
impl Dcmp1_Chunk_LiteralBody {

    /**
     * Whether this literal should be stored for use by future backreference chunks.
     * 
     * See the documentation of the `backreference_body` type for details about backreference chunks.
     */
    pub fn do_store(
        &self
    ) -> KResult<Ref<'_, bool>> {
        let _io = self._io.borrow();
        let _rrc = self._root.get_value().borrow().upgrade();
        let _prc = self._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        if self.f_do_store.get() {
            return Ok(self.do_store.borrow());
        }
        self.f_do_store.set(true);
        *self.do_store.borrow_mut() = (if *self.is_len_literal_separate()? { *self.tag() == 209 } else { ((((*self.tag() as u8) & (16 as u8)) as i32) != (0 as i32)) }) as bool;
        Ok(self.do_store.borrow())
    }

    /**
     * Whether the length of the literal is stored separately from the tag.
     */
    pub fn is_len_literal_separate(
        &self
    ) -> KResult<Ref<'_, bool>> {
        let _io = self._io.borrow();
        let _rrc = self._root.get_value().borrow().upgrade();
        let _prc = self._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        if self.f_is_len_literal_separate.get() {
            return Ok(self.is_len_literal_separate.borrow());
        }
        self.f_is_len_literal_separate.set(true);
        *self.is_len_literal_separate.borrow_mut() = (*self.tag() >= 208) as bool;
        Ok(self.is_len_literal_separate.borrow())
    }

    /**
     * The length of the literal data,
     * in bytes.
     * 
     * In practice,
     * this value is always greater than zero,
     * as there is no use in storing a zero-length literal.
     */
    pub fn len_literal(
        &self
    ) -> KResult<Ref<'_, i32>> {
        let _io = self._io.borrow();
        let _rrc = self._root.get_value().borrow().upgrade();
        let _prc = self._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        if self.f_len_literal.get() {
            return Ok(self.len_literal.borrow());
        }
        self.f_len_literal.set(true);
        *self.len_literal.borrow_mut() = (if *self.is_len_literal_separate()? { *self.len_literal_separate() } else { ((*self.len_literal_m1_in_tag()? as i32) + (1 as i32)) }) as i32;
        Ok(self.len_literal.borrow())
    }

    /**
     * The part of the tag byte that indicates the length of the literal data,
     * in bytes,
     * minus one.
     * 
     * If the tag byte is 0xd0 or 0xd1,
     * the length is stored in a separate byte after the tag byte and before the literal data.
     */
    pub fn len_literal_m1_in_tag(
        &self
    ) -> KResult<Ref<'_, i32>> {
        let _io = self._io.borrow();
        let _rrc = self._root.get_value().borrow().upgrade();
        let _prc = self._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        if self.f_len_literal_m1_in_tag.get() {
            return Ok(self.len_literal_m1_in_tag.borrow());
        }
        self.f_len_literal_m1_in_tag.set(true);
        if !(*self.is_len_literal_separate()?) {
            *self.len_literal_m1_in_tag.borrow_mut() = (((*self.tag() as u8) & (15 as u8))) as i32;
        }
        Ok(self.len_literal_m1_in_tag.borrow())
    }
}

/**
 * The length of the literal data,
 * in bytes.
 * 
 * This field is only present if the tag byte is 0xd0 or 0xd1.
 * In practice,
 * this only happens if the length is 0x11 or greater,
 * because smaller lengths can be encoded into the tag byte.
 */
impl Dcmp1_Chunk_LiteralBody {
    pub fn len_literal_separate(&self) -> Ref<'_, u8> {
        self.len_literal_separate.borrow()
    }
}

/**
 * The literal data.
 */
impl Dcmp1_Chunk_LiteralBody {
    pub fn literal(&self) -> Ref<'_, Vec<u8>> {
        self.literal.borrow()
    }
}
impl Dcmp1_Chunk_LiteralBody {
    pub fn _io(&self) -> Ref<'_, BytesReader> {
        self._io.borrow()
    }
}

/**
 * The body of a table lookup chunk.
 * This body is always empty.
 * 
 * This chunk always expands to two bytes (`value`),
 * determined from the tag byte using a fixed lookup table (`lookup_table`).
 * This lookup table is hardcoded in the decompressor and always the same for all compressed data.
 */

#[derive(Default, Debug, Clone)]
pub struct Dcmp1_Chunk_TableLookupBody {
    pub _root: SharedType<Dcmp1>,
    pub _parent: SharedType<Dcmp1_Chunk>,
    pub _self: SharedType<Self>,
    tag: RefCell<u8>,
    _io: RefCell<BytesReader>,
    f_lookup_table: Cell<bool>,
    lookup_table: RefCell<Vec<Vec<u8>>>,
    f_value: Cell<bool>,
    value: RefCell<Vec<u8>>,
}
impl KStruct for Dcmp1_Chunk_TableLookupBody {
    type Root = Dcmp1;
    type Parent = Dcmp1_Chunk;

    fn read<S: KStream>(
        self_rc: &OptRc<Self>,
        _io: &S,
        _root: SharedType<Self::Root>,
        _parent: SharedType<Self::Parent>,
    ) -> KResult<()> {
        *self_rc._io.borrow_mut() = _io.clone();
        self_rc._root.set(_root.get());
        self_rc._parent.set(_parent.get());
        self_rc._self.set(Ok(self_rc.clone()));
        let _rrc = self_rc._root.get_value().borrow().upgrade();
        let _prc = self_rc._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        Ok(())
    }
}
impl Dcmp1_Chunk_TableLookupBody {
    pub fn tag(&self) -> Ref<'_, u8> {
        self.tag.borrow()
    }
}
impl Dcmp1_Chunk_TableLookupBody {
    pub fn set_params(&mut self, tag: u8) {
        *self.tag.borrow_mut() = tag;
    }
}
impl Dcmp1_Chunk_TableLookupBody {

    /**
     * Fixed lookup table that maps tag byte numbers to two bytes each.
     * 
     * The entries in the lookup table are offset -
     * index 0 stands for tag 0xd5, 1 for 0xd6, etc.
     */
    pub fn lookup_table(
        &self
    ) -> KResult<Ref<'_, Vec<Vec<u8>>>> {
        let _io = self._io.borrow();
        let _rrc = self._root.get_value().borrow().upgrade();
        let _prc = self._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        if self.f_lookup_table.get() {
            return Ok(self.lookup_table.borrow());
        }
        self.f_lookup_table.set(true);
        *self.lookup_table.borrow_mut() = vec![vec![0x0u8, 0x0u8], vec![0x0u8, 0x1u8], vec![0x0u8, 0x2u8], vec![0x0u8, 0x3u8], vec![0x2eu8, 0x1u8], vec![0x3eu8, 0x1u8], vec![0x1u8, 0x1u8], vec![0x1eu8, 0x1u8], vec![0xffu8, 0xffu8], vec![0xeu8, 0x1u8], vec![0x31u8, 0x0u8], vec![0x11u8, 0x12u8], vec![0x1u8, 0x7u8], vec![0x33u8, 0x32u8], vec![0x12u8, 0x39u8], vec![0xedu8, 0x10u8], vec![0x1u8, 0x27u8], vec![0x23u8, 0x22u8], vec![0x1u8, 0x37u8], vec![0x7u8, 0x6u8], vec![0x1u8, 0x17u8], vec![0x1u8, 0x23u8], vec![0x0u8, 0xffu8], vec![0x0u8, 0x2fu8], vec![0x7u8, 0xeu8], vec![0xfdu8, 0x3cu8], vec![0x1u8, 0x35u8], vec![0x1u8, 0x15u8], vec![0x1u8, 0x2u8], vec![0x0u8, 0x7u8], vec![0x0u8, 0x3eu8], vec![0x5u8, 0xd5u8], vec![0x2u8, 0x1u8], vec![0x6u8, 0x7u8], vec![0x7u8, 0x8u8], vec![0x30u8, 0x1u8], vec![0x1u8, 0x33u8], vec![0x0u8, 0x10u8], vec![0x17u8, 0x16u8], vec![0x37u8, 0x3eu8], vec![0x36u8, 0x37u8]].to_vec();
        Ok(self.lookup_table.borrow())
    }

    /**
     * The two bytes that the tag byte expands to,
     * based on the fixed lookup table.
     */
    pub fn value(
        &self
    ) -> KResult<Ref<'_, Vec<u8>>> {
        let _io = self._io.borrow();
        let _rrc = self._root.get_value().borrow().upgrade();
        let _prc = self._parent.get_value().borrow().upgrade();
        let _r = _rrc.as_ref().unwrap();
        if self.f_value.get() {
            return Ok(self.value.borrow());
        }
        self.f_value.set(true);
        *self.value.borrow_mut() = self.lookup_table()?[((*self.tag() as u8) - (213 as u8)) as usize].to_vec();
        Ok(self.value.borrow())
    }
}
impl Dcmp1_Chunk_TableLookupBody {
    pub fn _io(&self) -> Ref<'_, BytesReader> {
        self._io.borrow()
    }
}