noak 0.6.3

A library for reading and writing java class files
Documentation
use crate::error::*;
use crate::mutf8;
use crate::reader::attributes::code;
use crate::reader::attributes::FromAttribute;
use crate::reader::cpool;
use crate::reader::decoding::*;
use crate::MStr;
use std::fmt;
use std::iter::FusedIterator;

#[derive(Clone)]
pub struct StackMapTable<'input> {
    iter: StackMapIter<'input>,
}

impl<'input> StackMapTable<'input> {
    #[must_use]
    pub fn iter(&self) -> StackMapIter<'input> {
        self.iter.clone()
    }
}

impl<'input> DecodeInto<'input> for StackMapTable<'input> {
    fn decode_into(mut decoder: Decoder<'input>) -> Result<Self, DecodeError> {
        let count = decoder.read()?;
        Ok(StackMapTable {
            iter: StackMapIter {
                decoder,
                remaining: count,
                current_offset: 0,
            },
        })
    }
}

impl<'input> FromAttribute<'input> for StackMapTable<'input> {
    const NAME: &'static MStr = mutf8!("StackMapTable");
}

impl<'input> fmt::Debug for StackMapTable<'input> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("StackMapTable").finish()
    }
}

#[derive(Clone)]
pub struct StackMapIter<'input> {
    decoder: Decoder<'input>,
    remaining: u16,
    current_offset: u32,
}

impl<'input> Iterator for StackMapIter<'input> {
    type Item = Result<(code::Index, StackMapFrame<'input>), DecodeError>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.remaining == 0 {
            None
        } else {
            self.remaining -= 1;
            let bytes_remaining = self.decoder.bytes_remaining() as u32;
            let stack_map_frame = decode_stack_map_frame(&mut self.decoder, self.current_offset);
            self.current_offset += bytes_remaining - self.decoder.bytes_remaining() as u32;
            Some(stack_map_frame)
        }
    }
}

impl<'input> FusedIterator for StackMapIter<'input> {}

impl<'input> fmt::Debug for StackMapIter<'input> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("StackMapIter").finish()
    }
}

#[derive(Debug, Clone)]
pub enum StackMapFrame<'input> {
    Same,
    SameExtended,
    Same1 {
        stack: VerificationType<'input>,
    },
    Same1Extended {
        stack: VerificationType<'input>,
    },
    Chop {
        to_chop: u8,
    },
    Append {
        locals: VerificationTypeIter<'input>,
    },
    Full {
        locals: VerificationTypeIter<'input>,
        stack: VerificationTypeIter<'input>,
    },
}

fn decode_stack_map_frame<'input>(
    decoder: &mut Decoder<'input>,
    current_offset: u32,
) -> Result<(code::Index, StackMapFrame<'input>), DecodeError> {
    let frame_type: u8 = decoder.read()?;
    match frame_type {
        0..=63 => {
            let index = code::Index::new(frame_type.into());
            Ok((index, StackMapFrame::Same))
        }
        64..=127 => {
            let index = code::Index::new(u32::from(frame_type - 64) + current_offset);
            let stack = decode_verification_type(decoder, current_offset)?;
            Ok((index, StackMapFrame::Same1 { stack }))
        }
        247 => {
            let index = code::Index::new(u32::from(decoder.read::<u16>()?) + current_offset);
            let stack = decode_verification_type(decoder, current_offset)?;
            Ok((index, StackMapFrame::Same1 { stack }))
        }
        248..=250 => {
            let to_chop = 251 - frame_type;
            let index = code::Index::new(u32::from(decoder.read::<u16>()?) + current_offset);
            Ok((index, StackMapFrame::Chop { to_chop }))
        }
        251 => {
            let index = code::Index::new(u32::from(decoder.read::<u16>()?) + current_offset);
            Ok((index, StackMapFrame::SameExtended))
        }
        252..=254 => {
            let index = code::Index::new(u32::from(decoder.read::<u16>()?) + current_offset);
            let locals = VerificationTypeIter::new(decoder, (frame_type - 251).into(), current_offset)?;
            Ok((index, StackMapFrame::Append { locals }))
        }
        255 => {
            let index = code::Index::new(u32::from(decoder.read::<u16>()?) + current_offset);

            let local_count = decoder.read()?;
            let locals = VerificationTypeIter::new(decoder, local_count, current_offset)?;

            let stack_count = decoder.read()?;
            let stack = VerificationTypeIter::new(decoder, stack_count, current_offset)?;

            Ok((index, StackMapFrame::Full { locals, stack }))
        }
        _ => Err(DecodeError::from_decoder(DecodeErrorKind::TagReserved, decoder)),
    }
}

#[derive(Debug, Copy, Clone)]
pub enum VerificationType<'input> {
    Top,
    Null,
    UninitializedThis,
    Object(cpool::Index<cpool::Class<'input>>),
    UninitializedVariable(code::Index),
    Integer,
    Long,
    Float,
    Double,
}

fn decode_verification_type<'input>(
    decoder: &mut Decoder<'input>,
    current_offset: u32,
) -> Result<VerificationType<'input>, DecodeError> {
    let tag: u8 = decoder.read()?;
    match tag {
        0x00 => Ok(VerificationType::Top),
        0x01 => Ok(VerificationType::Integer),
        0x02 => Ok(VerificationType::Float),
        0x03 => Ok(VerificationType::Double),
        0x04 => Ok(VerificationType::Long),
        0x05 => Ok(VerificationType::Null),
        0x06 => Ok(VerificationType::UninitializedThis),
        0x07 => Ok(VerificationType::Object(decoder.read()?)),
        0x08 => {
            let index = code::Index::new(current_offset + u32::from(decoder.read::<u16>()?));
            Ok(VerificationType::UninitializedVariable(index))
        }
        _ => Err(DecodeError::from_decoder(DecodeErrorKind::InvalidTag, decoder)),
    }
}

fn skip_verification_type<'input>(decoder: &mut Decoder<'input>) -> Result<(), DecodeError> {
    let tag: u8 = decoder.read()?;
    match tag {
        0x07 => {
            decoder.read::<cpool::Index<cpool::Class<'input>>>()?;
            Ok(())
        }
        0x08 => {
            decoder.read::<u16>()?;
            Ok(())
        }
        _ if tag < 0x07 => Ok(()),
        _ => Err(DecodeError::from_decoder(DecodeErrorKind::InvalidTag, decoder)),
    }
}

#[derive(Clone)]
pub struct VerificationTypeIter<'input> {
    decoder: Decoder<'input>,
    remaining: u16,
    current_offset: u32,
}

impl<'input> VerificationTypeIter<'input> {
    fn new(
        decoder: &mut Decoder<'input>,
        count: u16,
        current_offset: u32,
    ) -> Result<VerificationTypeIter<'input>, DecodeError> {
        let old_decoder = decoder.clone();
        for _ in 0..count {
            skip_verification_type(decoder)?;
        }
        Ok(VerificationTypeIter {
            decoder: old_decoder,
            remaining: count,
            current_offset,
        })
    }
}

impl<'input> Iterator for VerificationTypeIter<'input> {
    type Item = Result<VerificationType<'input>, DecodeError>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.remaining == 0 {
            None
        } else {
            self.remaining -= 1;
            let bytes_remaining = self.decoder.bytes_remaining() as u32;
            let verification_type = decode_verification_type(&mut self.decoder, self.current_offset);
            self.current_offset += bytes_remaining - self.decoder.bytes_remaining() as u32;
            Some(verification_type)
        }
    }
}

impl<'input> fmt::Debug for VerificationTypeIter<'input> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("VerificationTypeIter").finish()
    }
}