Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/rust/jxl/src/container/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 5 kB image not shown  

Quelle  mod.rs

  Sprache: Rust
 

// Copyright (c) the JPEG XL Project Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// Originally written for jxl-oxide.

pub mod box_header;
pub mod frame_index;
pub mod parse;

use box_header::*;
pub use parse::ParseEvent;
use parse::*;

/// Container format parser.
#[derive(Debug, Default)]
pub struct ContainerParser {
    state: DetectState,
    jxlp_index_state: JxlpIndexState,
    previous_consumed_bytes: usize,
}

#[derive(Debug, Default)]
enum DetectState {
    #[default]
    WaitingSignature,
    WaitingBoxHeader,
    WaitingJxlpIndex(ContainerBoxHeader),
    InAuxBox {
        #[allow(unused)]
        header: ContainerBoxHeader,
        bytes_left: Option<usize>,
    },
    InCodestream {
        kind: BitstreamKind,
        bytes_left: Option<usize>,
    },
}

/// Structure of the decoded bitstream.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum BitstreamKind {
    /// Decoder can't determine structure of the bitstream.
    Unknown,
    /// Bitstream is a direct JPEG XL codestream without box structure.
    BareCodestream,
    /// Bitstream is a JPEG XL container with box structure.
    Container,
    /// Bitstream is not a valid JPEG XL image.
    Invalid,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
enum JxlpIndexState {
    #[default]
    Initial,
    SingleJxlc,
    Jxlp(u32),
    JxlpFinished,
}

impl ContainerParser {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn kind(&self) -> BitstreamKind {
        match self.state {
            DetectState::WaitingSignature => BitstreamKind::Unknown,
            DetectState::WaitingBoxHeader
            | DetectState::WaitingJxlpIndex(..)
            | DetectState::InAuxBox { .. } => BitstreamKind::Container,
            DetectState::InCodestream { kind, .. } => kind,
        }
    }

    /// Parses input buffer and generates parser events.
    ///
    /// The parser might not fully consume the buffer. Use [`previous_consumed_bytes`] to get how
    /// many bytes are consumed. Bytes not consumed by the parser should be processed again.
    ///
    /// [`previous_consumed_bytes`]: ContainerParser::previous_consumed_bytes
    pub fn process_bytes<'inner, 'buf>(
        &'inner mut self,
        input: &'buf [u8],
    ) -> ParseEvents<'inner, 'buf> {
        ParseEvents::new(self, input)
    }

    /// Get how many bytes are consumed by the previous call to [`process_bytes`].
    ///
    /// Bytes not consumed by the parser should be processed again.
    ///
    /// [`process_bytes`]: ContainerParser::process_bytes
    pub fn previous_consumed_bytes(&self) -> usize {
        self.previous_consumed_bytes
    }
}

#[cfg(test)]
impl ContainerParser {
    pub(cratefn collect_codestream(input: &[u8]) -> crate::error::Result<Vec<u8>> {
        let mut parser = Self::new();
        let mut codestream = Vec::new();
        for event in parser.process_bytes(input) {
            match event? {
                ParseEvent::BitstreamKind(_) => {}
                ParseEvent::Codestream(buf) => {
                    codestream.extend_from_slice(buf);
                }
            }
        }
        Ok(codestream)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use test_log::test;

    #[rustfmt::skip]
    const HEADER: &[u8] = &[
        0x00, 0x00, 0x00, 0x0c, b'J', b'X', b'L', b' '0x0d, 0x0a, 0x87, 0x0a, 0x00, 0x00, 0x00, 0x14,
        b'f', b't', b'y', b'p', b'j', b'x', b'l', b' '0x00, 0x00, 0x00, 0x00, b'j', b'x', b'l', b' ',
    ];

    #[test]
    fn parse_partial() {
        arbtest::arbtest(|u| {
            // Prepare arbitrary container format data with two jxlp boxes.
            let total_len = u.arbitrary_len::<u8>()?;
            let mut codestream0 = vec![0u8; total_len / 2];
            u.fill_buffer(&mut codestream0)?;
            let mut codestream1 = vec![0u8; total_len - codestream0.len()];
            u.fill_buffer(&mut codestream1)?;

            let mut container = HEADER.to_vec();
            container.extend_from_slice(&(12 + codestream0.len() as u32).to_be_bytes());
            container.extend_from_slice(b"jxlp\x00\x00\x00\x00");
            container.extend_from_slice(&codestream0);

            container.extend_from_slice(&(12 + codestream1.len() as u32).to_be_bytes());
            container.extend_from_slice(b"jxlp\x80\x00\x00\x01");
            container.extend_from_slice(&codestream1);

            let mut expected = codestream0;
            expected.extend(codestream1);

            // Create a list of arbitrary splits.
            let mut tests = Vec::new();
            u.arbitrary_loop(Some(1), Some(10), |u| {
                let split_at_idx = u.choose_index(container.len())?;
                tests.push(container.split_at(split_at_idx));
                Ok(std::ops::ControlFlow::Continue(()))
            })?;

            // Test if split index doesn't affect final codestream.
            for (first, second) in tests {
                let mut codestream = Vec::new();
                let mut parser = ContainerParser::new();

                for event in parser.process_bytes(first) {
                    let event = event.unwrap();
                    if let ParseEvent::Codestream(data) = event {
                        codestream.extend_from_slice(data);
                    }
                }

                let consumed = parser.previous_consumed_bytes();
                let mut second_chunk = first[consumed..].to_vec();
                second_chunk.extend_from_slice(second);

                for event in parser.process_bytes(&second_chunk) {
                    let event = event.unwrap();
                    if let ParseEvent::Codestream(data) = event {
                        codestream.extend_from_slice(data);
                    }
                }

                assert_eq!(codestream, expected);
            }

            Ok(())
        });
    }
}

Messung V0.5 in Prozent
C=93 H=97 G=94

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.