aboutsummaryrefslogtreecommitdiff
path: root/matroska
diff options
context:
space:
mode:
Diffstat (limited to 'matroska')
-rw-r--r--matroska/Cargo.toml10
-rw-r--r--matroska/src/bin/mkvdump.rs28
-rw-r--r--matroska/src/block.rs91
-rw-r--r--matroska/src/error.rs24
-rw-r--r--matroska/src/lib.rs27
-rw-r--r--matroska/src/matroska.rs335
-rw-r--r--matroska/src/read.rs298
-rw-r--r--matroska/src/size.rs25
-rw-r--r--matroska/src/unflatten.rs83
-rw-r--r--matroska/src/write.rs382
10 files changed, 0 insertions, 1303 deletions
diff --git a/matroska/Cargo.toml b/matroska/Cargo.toml
deleted file mode 100644
index 23c9c5a..0000000
--- a/matroska/Cargo.toml
+++ /dev/null
@@ -1,10 +0,0 @@
-[package]
-name = "jellymatroska"
-version = "0.1.0"
-edition = "2021"
-
-[dependencies]
-ebml_derive = { path = "../ebml_derive" }
-log = "0.4.25"
-env_logger = "0.11.6"
-thiserror = "2.0.11"
diff --git a/matroska/src/bin/mkvdump.rs b/matroska/src/bin/mkvdump.rs
deleted file mode 100644
index 48420c6..0000000
--- a/matroska/src/bin/mkvdump.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2025 metamuffin <metamuffin.org>
-*/
-use jellymatroska::{matroska::MatroskaTag, read::EbmlReader};
-use std::{fs::File, io::BufReader};
-
-fn main() {
- env_logger::init_from_env("LOG");
- let path = std::env::args().nth(1).unwrap();
- let r = EbmlReader::new(BufReader::new(File::open(path).unwrap()));
-
- for tag in r {
- let (position, tag) = tag.unwrap();
- match tag {
- MatroskaTag::SimpleBlock(b) | MatroskaTag::Block(b) => {
- println!(
- "block t={} kf={} ts_off={}",
- b.track,
- b.flags.keyframe(),
- b.timestamp_off
- )
- }
- _ => println!("{} {tag:?}", position.unwrap_or(0)),
- }
- }
-}
diff --git a/matroska/src/block.rs b/matroska/src/block.rs
deleted file mode 100644
index 54d9de5..0000000
--- a/matroska/src/block.rs
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2025 metamuffin <metamuffin.org>
-*/
-use crate::{
- read::ReadExt,
- write::{vint_length, write_vint},
- ReadValue, Result, WriteValue,
-};
-use std::io::{Cursor, Write};
-
-#[derive(Debug, PartialEq, Clone, Copy)]
-pub enum LacingType {
- None,
- Xiph,
- FixedSize,
- Ebml,
-}
-
-#[derive(Debug, PartialEq, Clone)]
-pub struct Block {
- pub track: u64,
- pub flags: Flags,
- pub timestamp_off: i16,
- pub data: Vec<u8>,
-}
-
-#[derive(Debug, PartialEq, Clone)]
-pub struct Flags(u8);
-
-impl Flags {
- pub fn keyframe(&self) -> bool {
- self.0 & 0b10000000 != 0
- }
- pub fn lacing(&self) -> LacingType {
- match self.0 & 0b00000110 {
- 0b000 => LacingType::None,
- 0b010 => LacingType::Xiph,
- 0b100 => LacingType::FixedSize,
- 0b110 => LacingType::Ebml,
- _ => unreachable!(),
- }
- }
- pub fn discardable(&self) -> bool {
- self.0 & 0b00000001 != 0
- }
- pub fn invisible(&self) -> bool {
- self.0 & 0b00001000 != 0
- }
-}
-
-impl ReadValue for Block {
- fn from_buf(buf: &[u8]) -> Result<Self> {
- let (track, c) = Cursor::new(buf).read_vint_len()?;
- let timestamp_off = i16::from_be_bytes(buf[c..c + 2].try_into().unwrap());
- let flags = Flags(buf[c + 2]);
- let data = Vec::from(&buf[c + 3..]);
-
- Ok(Self {
- track,
- data,
- flags,
- timestamp_off,
- })
- }
-}
-
-impl WriteValue for Block {
- fn write_to(&self, w: &mut impl Write) -> Result<()> {
- write_vint(w, self.inner_len() as u64)?;
- write_vint(w, self.track)?;
- w.write_all(&self.timestamp_off.to_be_bytes())?;
- w.write_all(&[self.flags.0])?;
- w.write_all(&self.data)?;
- Ok(())
- }
- fn size(&self) -> usize {
- let il = self.inner_len();
- vint_length(il as u64) + il
- }
-}
-
-impl Block {
- fn inner_len(&self) -> usize {
- vint_length(self.track)
- + 2 // timestamp
- + 1 // flags
- + self.data.len()
- }
-}
diff --git a/matroska/src/error.rs b/matroska/src/error.rs
deleted file mode 100644
index d2bbcbf..0000000
--- a/matroska/src/error.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2025 metamuffin <metamuffin.org>
-*/
-use thiserror::Error;
-
-#[derive(Debug, Error)]
-pub enum Error {
- #[error("invalid padding")]
- InvalidPadding,
- #[error("varint too long")]
- VarintTooLong,
- #[error("global tags dont provide any context")]
- GlobalTagsAsContext,
- #[error("invalid length of a exact size type")]
- InvalidTypeLen,
- #[error("invalid utf8")]
- InvalidUTF8,
- #[error("unknown id")]
- UnknownID,
- #[error("io: {0}")]
- Io(#[from] std::io::Error),
-}
diff --git a/matroska/src/lib.rs b/matroska/src/lib.rs
deleted file mode 100644
index 1098ca6..0000000
--- a/matroska/src/lib.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2025 metamuffin <metamuffin.org>
-*/
-pub mod block;
-pub mod error;
-pub mod matroska;
-pub mod read;
-pub mod size;
-pub mod unflatten;
-pub mod write;
-
-pub use matroska::MatroskaTag;
-pub use read::ReadValue;
-pub use write::WriteValue;
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum Master {
- Collected(Vec<MatroskaTag>),
- Start,
- End,
-}
-
-pub(crate) use block::Block;
-pub(crate) use error::Error;
-pub(crate) type Result<T> = core::result::Result<T, Error>;
diff --git a/matroska/src/matroska.rs b/matroska/src/matroska.rs
deleted file mode 100644
index 50e12b9..0000000
--- a/matroska/src/matroska.rs
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2025 metamuffin <metamuffin.org>
-*/
-use ebml_derive::define_ebml;
-
-define_ebml! {
- global Crc32[0xbf]: Binary,
- global Void[0xec]: Binary,
-
- Ebml[0x1a45dfa3]: {
- EbmlVersion[0x4286]: Uint,
- EbmlReadVersion[0x42f7]: Uint,
- EbmlMaxIdLength[0x42f2]: Uint,
- EbmlMaxSizeLength[0x42f3]: Uint,
- DocType[0x4282]: Utf8,
- DocTypeVersion[0x4287]: Uint,
- DocTypeReadVersion[0x4285]: Uint,
- DocTypeExtension[0x4281]: {
- DocTypeExtensionName[0x4283]: Utf8,
- DocTypeExtensionVersion[0x4284]: Uint,
- },
- },
-
- Segment[0x18538067]: {
- Attachments[0x1941A469]: {
- AttachedFile[0x61A7]: {
- FileData[0x465C]: Binary,
- FileDescription[0x467E]: Utf8,
- FileMimeType[0x4660]: Utf8,
- FileName[0x466E]: Utf8,
- FileReferral[0x4675]: Binary,
- FileUID[0x46AE]: Uint,
- FileUsedEndTime[0x4662]: Uint,
- FileUsedStartTime[0x4661]: Uint,
- },
- },
-
- Chapters[0x1043A770]: {
- EditionEntry[0x45B9]: {
- ChapterAtom[0xB6]: {
- ChapProcess[0x6944]: {
- ChapProcessCodecID[0x6955]: Uint,
- ChapProcessCommand[0x6911]: {
- ChapProcessData[0x6933]: Binary,
- ChapProcessTime[0x6922]: Uint,
- },
- ChapProcessPrivate[0x450D]: Binary,
- },
- ChapterDisplay[0x80]: {
- ChapCountry[0x437E]: Utf8,
- ChapLanguage[0x437C]: Utf8,
- ChapLanguageIETF[0x437D]: Utf8,
- ChapString[0x85]: Utf8,
- },
- ChapterFlagEnabled[0x4598]: Uint,
- ChapterFlagHidden[0x98]: Uint,
- ChapterPhysicalEquiv[0x63C3]: Uint,
- ChapterSegmentEditionUID[0x6EBC]: Uint,
- ChapterSegmentUID[0x6E67]: Binary,
- ChapterStringUID[0x5654]: Utf8,
- ChapterTimeEnd[0x92]: Uint,
- ChapterTimeStart[0x91]: Uint,
- ChapterUID[0x73C4]: Uint,
- ChapterTrack[0x8F]: {
- ChapterTrackUID[0x89]: Uint,
- },
- },
- EditionFlagDefault[0x45DB]: Uint,
- EditionFlagHidden[0x45BD]: Uint,
- EditionFlagOrdered[0x45DD]: Uint,
- EditionUID[0x45BC]: Uint,
- },
- },
-
- Cluster[0x1F43B675]: {
- BlockGroup[0xA0]: {
- Block[0xA1]: Block,
- BlockAdditions[0x75A1]: {
- BlockMore[0xA6]: {
- BlockAddID[0xEE]: Uint,
- BlockAdditional[0xA5]: Binary,
- },
- },
- BlockDuration[0x9B]: Uint,
- BlockVirtual[0xA2]: Binary,
- CodecState[0xA4]: Binary,
- DiscardPadding[0x75A2]: Int,
- ReferenceBlock[0xFB]: Int,
- ReferenceFrame[0xC8]: {
- ReferenceOffset[0xC9]: Uint,
- ReferenceTimestamp[0xCA]: Uint,
- },
- ReferencePriority[0xFA]: Uint,
- ReferenceVirtual[0xFD]: Int,
- Slices[0x8E]: {
- TimeSlice[0xE8]: {
- BlockAdditionID[0xCB]: Uint,
- Delay[0xCE]: Uint,
- FrameNumber[0xCD]: Uint,
- LaceNumber[0xCC]: Uint,
- SliceDuration[0xCF]: Uint,
- },
- },
- },
- EncryptedBlock[0xAF]: Binary,
- Position[0xA7]: Uint,
- PrevSize[0xAB]: Uint,
- SilentTracks[0x5854]: {
- SilentTrackNumber[0x58D7]: Uint,
- },
- SimpleBlock[0xA3]: Block,
- Timestamp[0xE7]: Uint,
- },
-
- Cues[0x1C53BB6B]: {
- CuePoint[0xBB]: {
- CueTime[0xB3]: Uint,
- CueTrackPositions[0xB7]: {
- CueBlockNumber[0x5378]: Uint,
- CueClusterPosition[0xF1]: Uint,
- CueCodecState[0xEA]: Uint,
- CueDuration[0xB2]: Uint,
- CueReference[0xDB]: {
- CueRefCluster[0x97]: Uint,
- CueRefCodecState[0xEB]: Uint,
- CueRefNumber[0x535F]: Uint,
- CueRefTime[0x96]: Uint,
- },
- CueRelativePosition[0xF0]: Uint,
- CueTrack[0xF7]: Uint,
- },
- },
- },
-
- Info[0x1549A966]: {
- ChapterTranslate[0x6924]: {
- ChapterTranslateCodec[0x69BF]: Uint,
- ChapterTranslateEditionUID[0x69FC]: Uint,
- ChapterTranslateID[0x69A5]: Binary,
- },
- DateUTC[0x4461]: Int,
- Duration[0x4489]: Float,
- MuxingApp[0x4D80]: Utf8,
- NextFilename[0x3E83BB]: Utf8,
- NextUID[0x3EB923]: Binary,
- PrevFilename[0x3C83AB]: Utf8,
- PrevUID[0x3CB923]: Binary,
- SegmentFamily[0x4444]: Binary,
- SegmentFilename[0x7384]: Utf8,
- SegmentUID[0x73A4]: Binary,
- TimestampScale[0x2AD7B1]: Uint,
- Title[0x7BA9]: Utf8,
- WritingApp[0x5741]: Utf8,
- },
-
- SeekHead[0x114D9B74]: {
- Seek[0x4DBB]: {
- SeekID[0x53AB]: Binary,
- SeekPosition[0x53AC]: Uint,
- },
- },
-
- Tags[0x1254C367]: {
- Tag[0x7373]: {
- SimpleTag[0x67C8]: {
- TagBinary[0x4485]: Binary,
- TagDefault[0x4484]: Uint,
- TagDefaultBogus[0x44B4]: Uint,
- TagLanguage[0x447A]: Utf8,
- TagLanguageIETF[0x447B]: Utf8,
- TagName[0x45A3]: Utf8,
- TagString[0x4487]: Utf8,
- },
- Targets[0x63C0]: {
- TagAttachmentUID[0x63C6]: Uint,
- TagChapterUID[0x63C4]: Uint,
- TagEditionUID[0x63C9]: Uint,
- TagTrackUID[0x63C5]: Uint,
- TargetType[0x63CA]: Utf8,
- TargetTypeValue[0x68CA]: Uint,
- },
- },
- },
-
- Tracks[0x1654AE6B]: {
- TrackEntry[0xAE]: {
- AttachmentLink[0x7446]: Uint,
- Audio[0xE1]: {
- BitDepth[0x6264]: Uint,
- ChannelPositions[0x7D7B]: Binary,
- Channels[0x9F]: Uint,
- OutputSamplingFrequency[0x78B5]: Float,
- SamplingFrequency[0xB5]: Float,
- },
- BlockAdditionMapping[0x41E4]: {
- BlockAddIDExtraData[0x41ED]: Binary,
- BlockAddIDName[0x41A4]: Utf8,
- BlockAddIDType[0x41E7]: Uint,
- BlockAddIDValue[0x41F0]: Uint,
- },
- CodecDecodeAll[0xAA]: Uint,
- CodecDelay[0x56AA]: Uint,
- CodecDownloadURL[0x26B240]: Utf8,
- CodecID[0x86]: Utf8,
- CodecInfoURL[0x3B4040]: Utf8,
- CodecName[0x258688]: Utf8,
- CodecPrivate[0x63A2]: Binary,
- CodecSettings[0x3A9697]: Utf8,
- ContentEncodings[0x6D80]: {
- ContentEncoding[0x6240]: {
- ContentCompression[0x5034]: {
- ContentCompAlgo[0x4254]: Uint,
- ContentCompSettings[0x4255]: Binary,
- },
- ContentEncodingOrder[0x5031]: Uint,
- ContentEncodingScope[0x5032]: Uint,
- ContentEncodingType[0x5033]: Uint,
- ContentEncryption[0x5035]: {
- ContentEncAESSettings[0x47E7]: {
- AESSettingsCipherMode[0x47E8]: Uint,
- },
- ContentEncAlgo[0x47E1]: Uint,
- ContentEncKeyID[0x47E2]: Binary,
- ContentSigAlgo[0x47E5]: Uint,
- ContentSigHashAlgo[0x47E6]: Uint,
- ContentSigKeyID[0x47E4]: Binary,
- ContentSignature[0x47E3]: Binary,
- },
- },
- },
- DefaultDecodedFieldDuration[0x234E7A]: Uint,
- DefaultDuration[0x23E383]: Uint,
- FlagCommentary[0x55AF]: Uint,
- FlagDefault[0x88]: Uint,
- FlagEnabled[0xB9]: Uint,
- FlagForced[0x55AA]: Uint,
- FlagHearingImpaired[0x55AB]: Uint,
- FlagLacing[0x9C]: Uint,
- FlagOriginal[0x55AE]: Uint,
- FlagTextDescriptions[0x55AD]: Uint,
- FlagVisualImpaired[0x55AC]: Uint,
- Language[0x22B59C]: Utf8,
- LanguageIETF[0x22B59D]: Utf8,
- MaxBlockAdditionID[0x55EE]: Uint,
- MaxCache[0x6DF8]: Uint,
- MinCache[0x6DE7]: Uint,
- Name[0x536E]: Utf8,
- SeekPreRoll[0x56BB]: Uint,
- TrackNumber[0xD7]: Uint,
- TrackOffset[0x537F]: Int,
- TrackOperation[0xE2]: {
- TrackCombinePlanes[0xE3]: {
- TrackPlane[0xE4]: {
- TrackPlaneType[0xE6]: Uint,
- TrackPlaneUID[0xE5]: Uint,
- },
- },
- TrackJoinBlocks[0xE9]: {
- TrackJoinUID[0xED]: Uint,
- },
- },
- TrackOverlay[0x6FAB]: Uint,
- TrackTimestampScale[0x23314F]: Float,
- TrackTranslate[0x6624]: {
- TrackTranslateCodec[0x66BF]: Uint,
- TrackTranslateEditionUID[0x66FC]: Uint,
- TrackTranslateTrackID[0x66A5]: Binary,
- },
- TrackType[0x83]: Uint,
- TrackUID[0x73C5]: Uint,
- TrickMasterTrackSegmentUID[0xC4]: Binary,
- TrickMasterTrackUID[0xC7]: Uint,
- TrickTrackFlag[0xC6]: Uint,
- TrickTrackSegmentUID[0xC1]: Binary,
- TrickTrackUID[0xC0]: Uint,
- Video[0xE0]: {
- AlphaMode[0x53C0]: Uint,
- AspectRatioType[0x54B3]: Uint,
- Colour[0x55B0]: {
- BitsPerChannel[0x55B2]: Uint,
- CbSubsamplingHorz[0x55B5]: Uint,
- CbSubsamplingVert[0x55B6]: Uint,
- ChromaSitingHorz[0x55B7]: Uint,
- ChromaSitingVert[0x55B8]: Uint,
- ChromaSubsamplingHorz[0x55B3]: Uint,
- ChromaSubsamplingVert[0x55B4]: Uint,
- MasteringMetadata[0x55D0]: {
- LuminanceMax[0x55D9]: Float,
- LuminanceMin[0x55DA]: Float,
- PrimaryBChromaticityX[0x55D5]: Float,
- PrimaryBChromaticityY[0x55D6]: Float,
- PrimaryGChromaticityX[0x55D3]: Float,
- PrimaryGChromaticityY[0x55D4]: Float,
- PrimaryRChromaticityX[0x55D1]: Float,
- PrimaryRChromaticityY[0x55D2]: Float,
- WhitePointChromaticityX[0x55D7]: Float,
- WhitePointChromaticityY[0x55D8]: Float,
- },
- MatrixCoefficients[0x55B1]: Uint,
- MaxCLL[0x55BC]: Uint,
- MaxFALL[0x55BD]: Uint,
- Primaries[0x55BB]: Uint,
- Range[0x55B9]: Uint,
- TransferCharacteristics[0x55BA]: Uint,
- },
- DisplayHeight[0x54BA]: Uint,
- DisplayUnit[0x54B2]: Uint,
- DisplayWidth[0x54B0]: Uint,
- FieldOrder[0x9D]: Uint,
- FlagInterlaced[0x9A]: Uint,
- FrameRate[0x2383E3]: Float,
- GammaValue[0x2FB523]: Float,
- OldStereoMode[0x53B9]: Uint,
- PixelCropBottom[0x54AA]: Uint,
- PixelCropLeft[0x54CC]: Uint,
- PixelCropRight[0x54DD]: Uint,
- PixelCropTop[0x54BB]: Uint,
- PixelHeight[0xBA]: Uint,
- PixelWidth[0xB0]: Uint,
- Projection[0x7670]: {
- ProjectionPosePitch[0x7674]: Float,
- ProjectionPoseRoll[0x7675]: Float,
- ProjectionPoseYaw[0x7673]: Float,
- ProjectionPrivate[0x7672]: Binary,
- ProjectionType[0x7671]: Uint,
- },
- StereoMode[0x53B8]: Uint,
- UncompressedFourCC[0x2EB524]: Binary,
- },
- },
- },
- },
-}
diff --git a/matroska/src/read.rs b/matroska/src/read.rs
deleted file mode 100644
index c3d06fa..0000000
--- a/matroska/src/read.rs
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2025 metamuffin <metamuffin.org>
-*/
-use crate::{error::Error, matroska::MatroskaTag, size::EbmlSize, Master, Result};
-use log::{debug, warn};
-use std::{
- collections::VecDeque,
- io::{Read, Seek, SeekFrom},
-};
-
-trait ReadAndSeek: Read + Seek {}
-impl<T: Read + Seek> ReadAndSeek for T {}
-
-#[derive(Debug, Clone, Copy)]
-pub struct StackTag {
- end: Option<u64>,
- id: u64,
-}
-
-pub struct EbmlReader {
- inner: Box<dyn ReadAndSeek>,
- stack: Vec<StackTag>,
- queue: VecDeque<(Option<u64>, MatroskaTag)>,
- position: u64,
-}
-
-impl Read for EbmlReader {
- fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
- let r = self.inner.read(buf)?;
- self.position += r as u64;
- Ok(r)
- }
-}
-
-impl EbmlReader {
- pub fn new<T: Seek + Read + 'static>(inner: T) -> Self {
- Self {
- queue: VecDeque::new(),
- inner: Box::new(inner),
- stack: vec![],
- position: 0,
- }
- }
-
- #[inline]
- pub fn read_byte(&mut self) -> Result<u8> {
- let mut b = [0u8];
- self.inner.read_exact(&mut b).map_err(Error::Io)?;
- self.position += 1;
- Ok(b[0])
- }
-
- pub fn read_buf(&mut self, size: impl Into<usize>) -> Result<Vec<u8>> {
- let size = size.into();
- let mut b = vec![0u8; size];
- self.inner.read_exact(&mut b).map_err(Error::Io)?;
- self.position += size as u64;
- Ok(b)
- }
-
- pub fn read_vint_len(&mut self) -> Result<(u64, usize)> {
- let s = self.read_byte()?;
- let len = s.leading_zeros() + 1;
- if len > 8 {
- Err(Error::VarintTooLong)?
- }
- let mut value = s as u64;
- value -= 1 << (8 - len);
- for _ in 1..len {
- value <<= 8;
- value += self.read_byte()? as u64;
- }
- Ok((value, len as usize))
- }
-
- #[inline]
- pub fn read_vint(&mut self) -> Result<u64> {
- Ok(self.read_vint_len()?.0)
- }
-
- #[inline]
- pub fn read_utf8(&mut self, size: impl Into<usize>) -> Result<String> {
- let b = self.read_buf(size)?;
- String::from_utf8(b).map_err(|_| Error::InvalidUTF8)
- }
-
- #[inline]
- pub fn read_tag_id(&mut self) -> Result<u64> {
- let (value, len) = self.read_vint_len()?;
- Ok(value + (1 << (7 * len)))
- }
-
- #[inline]
- pub fn read_tag_size(&mut self) -> Result<EbmlSize> {
- Ok(EbmlSize::from_vint(self.read_vint_len()?))
- }
-
- /// reads *some* amount of tags from the stream and pushes it to the queue.
- pub fn read_stuff(&mut self) -> Result<()> {
- while let Some(e) = self.stack.last().copied() {
- if let Some(end) = e.end {
- if self.position >= end {
- if self.position != end {
- warn!("we missed the end by {} bytes", self.position - end)
- }
- self.stack.pop();
- self.queue
- .push_back((None, MatroskaTag::construct_master(e.id, Master::End)?));
- } else {
- break;
- }
- } else {
- break;
- }
- }
-
- let start_position = self.position;
- let id = self.read_tag_id()?;
- let size = self.read_tag_size()?;
- let is_master = MatroskaTag::is_master(id)?;
- let tag = if is_master {
- MatroskaTag::construct_master(id, Master::Start)?
- } else {
- let data = self.read_buf(size.some().unwrap())?;
- MatroskaTag::parse(id, &data)?
- };
-
- if let Some(path) = tag.path() {
- // we have slightly different rules for closing tags implicitly
- // this closes as many tags as needed to make the next tag a valid child
- while let Some(stag @ StackTag { end: None, .. }) = self.stack.last() {
- if path.last() == Some(&stag.id) {
- break;
- } else {
- let end =
- MatroskaTag::construct_master(self.stack.pop().unwrap().id, Master::End)?;
- self.queue.push_back((None, end));
- }
- }
- }
-
- if is_master {
- self.stack.push(StackTag {
- end: size.some().map(|s| s as u64 + self.position),
- id,
- });
- }
- self.queue.push_back((Some(start_position), tag));
- Ok(())
- }
-
- /// context should be the next expected tag, such that the stack can be derived from its path.
- pub fn seek(&mut self, position: u64, context: MatroskaTag) -> Result<()> {
- let path = context.path().ok_or(Error::GlobalTagsAsContext)?;
- debug!(
- "seeking to {position} with a context restored from path {:x?}",
- path
- );
- self.queue.clear();
- self.position = position;
- self.inner.seek(SeekFrom::Start(position))?;
- self.stack = path
- .iter()
- .map(|id| StackTag { id: *id, end: None })
- .collect();
- Ok(())
- }
-}
-
-impl Iterator for EbmlReader {
- type Item = Result<(Option<u64>, MatroskaTag)>;
- fn next(&mut self) -> Option<Self::Item> {
- if let Some(t) = self.queue.pop_front() {
- // match t {
- // MatroskaTag::SimpleBlock(_) | MatroskaTag::Block(_) => (),
- // _ => debug!("reader yield: {t:?}"),
- // };
- Some(Ok(t))
- } else {
- match self.read_stuff() {
- Ok(()) => self.next(),
- // in case we reached the end (error: failed to fill whole buffer),
- // return the rest in the queue and pop all items of the stack
- Err(e) => {
- // TODO this is horrible, should use a custom error enum instead
- if format!("{e}").as_str() == "failed to fill whole buffer" {
- match self.queue.pop_front() {
- Some(q) => Some(Ok(q)),
- None => match self.stack.pop() {
- Some(q) => Some(Ok((
- None,
- MatroskaTag::construct_master(q.id, Master::End).unwrap(),
- ))),
- None => Some(Err(e)),
- },
- }
- } else {
- Some(Err(e))
- }
- }
- }
- }
- }
-}
-
-pub trait ReadValue: Sized {
- fn from_buf(buf: &[u8]) -> Result<Self>;
-}
-
-impl ReadValue for u64 {
- fn from_buf(buf: &[u8]) -> Result<Self> {
- if buf.len() > 8 {
- Err(Error::InvalidTypeLen)?
- }
- let mut val = 0u64;
- for byte in buf {
- val <<= 8;
- val |= *byte as u64;
- }
- Ok(val)
- }
-}
-impl ReadValue for i64 {
- fn from_buf(buf: &[u8]) -> Result<Self> {
- if buf.len() > 8 {
- Err(Error::InvalidTypeLen)?
- }
- Ok(if buf[0] > 127 {
- if buf.len() == 8 {
- i64::from_be_bytes(buf.try_into().unwrap())
- } else {
- -((1 << (buf.len() * 8)) - (u64::from_buf(buf)? as i64))
- }
- } else {
- u64::from_buf(buf)? as i64
- })
- }
-}
-impl ReadValue for f64 {
- fn from_buf(buf: &[u8]) -> Result<Self> {
- Ok(if buf.len() == 4 {
- f32::from_be_bytes(buf.try_into().unwrap()) as f64
- } else if buf.len() == 8 {
- f64::from_be_bytes(buf.try_into().unwrap())
- } else {
- Err(Error::InvalidTypeLen)?
- })
- }
-}
-
-impl ReadValue for Vec<u8> {
- fn from_buf(buf: &[u8]) -> Result<Self> {
- Ok(buf.to_vec())
- }
-}
-impl ReadValue for String {
- fn from_buf(buf: &[u8]) -> Result<Self> {
- String::from_utf8(Vec::from(buf)).map_err(|_| Error::InvalidUTF8)
- }
-}
-impl ReadValue for Master {
- fn from_buf(_: &[u8]) -> Result<Self> {
- panic!("master shall not be read like this")
- }
-}
-
-pub trait ReadExt: Read {
- fn read_byte(&mut self) -> Result<u8>;
- fn read_vint_len(&mut self) -> Result<(u64, usize)>;
- fn read_vint(&mut self) -> Result<u64>;
-}
-impl<T: Read> ReadExt for T {
- fn read_byte(&mut self) -> Result<u8> {
- let mut b = [0u8];
- self.read_exact(&mut b).map_err(Error::Io)?;
- Ok(b[0])
- }
- fn read_vint_len(&mut self) -> Result<(u64, usize)> {
- let s = self.read_byte()?;
- let len = s.leading_zeros() + 1;
- if len > 8 {
- Err(Error::VarintTooLong)?
- }
- let mut value = s as u64;
- value -= 1 << (8 - len);
- for _ in 1..len {
- value <<= 8;
- value += self.read_byte()? as u64;
- }
- Ok((value, len as usize))
- }
- #[inline]
- fn read_vint(&mut self) -> Result<u64> {
- Ok(self.read_vint_len()?.0)
- }
-}
diff --git a/matroska/src/size.rs b/matroska/src/size.rs
deleted file mode 100644
index 7ef0de9..0000000
--- a/matroska/src/size.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2025 metamuffin <metamuffin.org>
-*/
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum EbmlSize {
- Exact(usize),
- Unknown,
-}
-impl EbmlSize {
- pub fn from_vint((value, len): (u64, usize)) -> EbmlSize {
- if value == ((1 << (7 * len)) - 1) {
- Self::Unknown
- } else {
- Self::Exact(value as usize)
- }
- }
- pub fn some(self) -> Option<usize> {
- match self {
- EbmlSize::Exact(s) => Some(s),
- EbmlSize::Unknown => None,
- }
- }
-}
diff --git a/matroska/src/unflatten.rs b/matroska/src/unflatten.rs
deleted file mode 100644
index d5fb887..0000000
--- a/matroska/src/unflatten.rs
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2025 metamuffin <metamuffin.org>
-*/
-use crate::{matroska::MatroskaTag, Master, Result};
-
-pub struct Unflat<'a> {
- pub item: MatroskaTag,
- pub children: Option<Unflatten<'a>>,
- pub position: Option<u64>,
-}
-
-pub struct Unflatten<'a> {
- inner: &'a mut dyn Iterator<Item = Result<(Option<u64>, MatroskaTag)>>,
- stop: bool,
- end: Option<MatroskaTag>,
-}
-
-impl<'a> Unflatten<'a> {
- pub fn new(inner: &'a mut dyn Iterator<Item = Result<(Option<u64>, MatroskaTag)>>) -> Self {
- Self {
- inner,
- stop: false,
- end: None,
- }
- }
- pub fn new_with_end(
- inner: &'a mut dyn Iterator<Item = Result<(Option<u64>, MatroskaTag)>>,
- start: MatroskaTag,
- ) -> Self {
- Self {
- inner,
- stop: false,
- end: Some(MatroskaTag::construct_master(start.id(), Master::End).unwrap()),
- }
- }
- pub fn exit_dirty(&mut self) {
- self.stop = true;
- }
-
- pub fn n(&mut self) -> Option<Result<Unflat<'_>>> {
- if self.stop {
- return None;
- }
- match self.inner.next() {
- None => None,
- Some(Err(e)) => Some(Err(e)),
- Some(Ok((position, item))) => {
- let master = MatroskaTag::is_master(item.id()).unwrap();
- if Some(&item) == self.end.as_ref() {
- self.stop = true;
- None
- } else {
- Some(Ok(Unflat {
- position,
- children: if master {
- let end =
- MatroskaTag::construct_master(item.id(), Master::End).unwrap();
- if end == item {
- return None;
- }
- Some(Unflatten {
- inner: self.inner,
- stop: false,
- end: Some(end),
- })
- } else {
- None
- },
- item,
- }))
- }
- }
- }
- }
-}
-
-impl Drop for Unflatten<'_> {
- fn drop(&mut self) {
- while self.n().is_some() {}
- }
-}
diff --git a/matroska/src/write.rs b/matroska/src/write.rs
deleted file mode 100644
index 58923c6..0000000
--- a/matroska/src/write.rs
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2025 metamuffin <metamuffin.org>
-*/
-use crate::{error::Error, matroska::MatroskaTag, size::EbmlSize, Master, Result};
-use log::debug;
-use std::io::{Seek, Write};
-
-pub struct EbmlWriter<W> {
- inner: W,
- position: usize,
-}
-
-impl<W: Write> EbmlWriter<W> {
- pub fn new(inner: W, position: usize) -> Self {
- Self { inner, position }
- }
-
- pub fn position(&self) -> usize {
- self.position
- }
-
- pub fn write_padding(&mut self, position: usize) -> Result<()> {
- debug!("padding up to {position}");
- let mut size = position - self.position;
- match size {
- 0 => return Ok(()),
- 1 => Err(Error::InvalidPadding)?,
- _ => (),
- }
- size -= 1; // subtract tag size
- size -= 4; // subtract vint size
-
- // match size {
- // _ if size < (1 << 7) => size -= 1,
- // _ if size < (1 << 14) => size -= 2,
- // _ if size < (1 << 21) => size -= 3,
- // _ if size < (1 << 28) => size -= 4,
- // _ if size < (1 << 35) => size -= 5,
- // _ => bail!("padding too large"),
- // }
-
- self.write_all(&[0xec])?;
- self.write_vint_len(size.try_into().unwrap(), 4)?;
- self.write_all(&vec![0; size])?;
- Ok(())
- }
-
- #[inline]
- pub fn write_tag(&mut self, tag: &MatroskaTag) -> Result<()> {
- tag.write_full(self)?;
- Ok(())
- }
-
- pub fn write_vint_len(&mut self, i: u64, len: usize) -> Result<()> {
- let mut bytes = i.to_be_bytes();
- let trunc = &mut bytes[(8 - len)..];
- trunc[0] |= 1 << (8 - len);
- self.write_all(trunc)?;
- Ok(())
- }
-}
-
-impl<W: Seek> Seek for EbmlWriter<W> {
- fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
- self.inner.seek(pos)?;
- match pos {
- std::io::SeekFrom::Start(s) => self.position = s as usize,
- std::io::SeekFrom::End(_) => unimplemented!(),
- std::io::SeekFrom::Current(s) => self.position += s as usize,
- }
- Ok(self.position as u64)
- }
-}
-
-impl<W: Write> Write for EbmlWriter<W> {
- fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
- let size = self.inner.write(buf)?;
- self.position += size;
- Ok(size)
- }
-
- fn flush(&mut self) -> std::io::Result<()> {
- todo!()
- }
-}
-
-impl MatroskaTag {
- pub fn write_full(&self, w: &mut impl Write) -> Result<()> {
- for b in self.id().to_be_bytes().iter().skip_while(|&v| *v == 0u8) {
- w.write_all(&[*b])?;
- }
- self.write(w)?;
- Ok(())
- }
- pub fn size_full(&self) -> usize {
- (8 - self.id().leading_zeros() as usize / 8) + self.size()
- }
-}
-
-pub fn write_vint(w: &mut impl Write, i: u64) -> Result<()> {
- if i > (1 << 56) - 1 {
- Err(Error::VarintTooLong)?
- }
- let len = (64 - i.leading_zeros() as usize) / 7 + 1;
- let mut bytes = i.to_be_bytes();
- let trunc = &mut bytes[(8 - len)..];
- trunc[0] |= 1 << (8 - len);
- w.write_all(trunc)?;
- Ok(())
-}
-
-/// this routine works only, if the varint is as small as it can possibly be.
-/// thats not always what we do though - see below
-pub fn vint_length(v: u64) -> usize {
- let mut len = 1;
- while len <= 8 {
- if v < (1 << ((7 * len) - 1)) {
- break;
- }
- len += 1;
- }
- len
-}
-pub fn bad_vint_length(v: u64) -> usize {
- match 64 - v.leading_zeros() {
- x if x <= 8 => 1,
- x if x <= 16 => 2,
- x if x <= 32 => 4,
- _ => 8,
- }
-}
-
-pub trait WriteValue {
- /// writes the contents of a tag, including the size but excluding the id.
- fn write_to(&self, w: &mut impl Write) -> Result<()>;
- fn size(&self) -> usize;
-}
-
-impl WriteValue for i64 {
- fn write_to(&self, w: &mut impl Write) -> Result<()> {
- match 64 - self.leading_zeros() {
- x if x <= 8 => {
- w.write_all(&[0x81])?;
- w.write_all(&(*self as i8).to_be_bytes())?;
- }
- x if x <= 16 => {
- w.write_all(&[0x82])?;
- w.write_all(&(*self as i16).to_be_bytes())?;
- }
- x if x <= 32 => {
- w.write_all(&[0x84])?;
- w.write_all(&(*self as i32).to_be_bytes())?;
- }
- _ => {
- w.write_all(&[0x88])?;
- w.write_all(&self.to_be_bytes())?;
- }
- };
- Ok(())
- }
-
- fn size(&self) -> usize {
- 1 + match 64 - self.leading_zeros() {
- x if x <= 8 => 1,
- x if x <= 16 => 2,
- x if x <= 32 => 4,
- _ => 8,
- }
- }
-}
-impl WriteValue for u64 {
- fn write_to(&self, w: &mut impl Write) -> Result<()> {
- match 64 - self.leading_zeros() {
- x if x <= 8 => {
- w.write_all(&[0x81])?;
- w.write_all(&(*self as u8).to_be_bytes())?;
- }
- x if x <= 16 => {
- w.write_all(&[0x82])?;
- w.write_all(&(*self as u16).to_be_bytes())?;
- }
- x if x <= 32 => {
- w.write_all(&[0x84])?;
- w.write_all(&(*self as u32).to_be_bytes())?;
- }
- _ => {
- w.write_all(&[0x88])?;
- w.write_all(&self.to_be_bytes())?;
- }
- };
- Ok(())
- }
- fn size(&self) -> usize {
- 1 + match 64 - self.leading_zeros() {
- x if x <= 8 => 1,
- x if x <= 16 => 2,
- x if x <= 32 => 4,
- _ => 8,
- }
- }
-}
-impl WriteValue for f64 {
- fn write_to(&self, w: &mut impl Write) -> Result<()> {
- w.write_all(&[0x88])?;
- w.write_all(&self.to_be_bytes())?;
- Ok(())
- }
- fn size(&self) -> usize {
- 1 + 8
- }
-}
-impl WriteValue for Vec<u8> {
- fn write_to(&self, w: &mut impl Write) -> Result<()> {
- write_vint(w, self.len() as u64)?;
- w.write_all(self)?;
- Ok(())
- }
-
- fn size(&self) -> usize {
- vint_length(self.len() as u64) + self.len()
- }
-}
-impl WriteValue for String {
- fn write_to(&self, w: &mut impl Write) -> Result<()> {
- let sl = self.as_bytes();
- write_vint(w, sl.len() as u64)?;
- w.write_all(sl)?;
- Ok(())
- }
-
- fn size(&self) -> usize {
- vint_length(self.len() as u64) + self.len()
- }
-}
-impl WriteValue for EbmlSize {
- fn write_to(&self, w: &mut impl Write) -> Result<()> {
- match self {
- EbmlSize::Exact(s) => write_vint(w, *s as u64)?,
- EbmlSize::Unknown => w.write_all(&[0xff])?,
- }
- Ok(())
- }
- fn size(&self) -> usize {
- match self {
- EbmlSize::Exact(s) => vint_length(*s as u64),
- EbmlSize::Unknown => 1,
- }
- }
-}
-
-impl WriteValue for Master {
- fn write_to(&self, w: &mut impl Write) -> Result<()> {
- match self {
- Master::Start => EbmlSize::Unknown.write_to(w),
- Master::End => {
- unreachable!()
- }
- Master::Collected(c) => {
- let mut size = 0;
- for c in c {
- size += c.size_full();
- }
- EbmlSize::Exact(size).write_to(w)?;
- for c in c {
- c.write_full(w)?;
- }
- Ok(())
- }
- }
- }
- fn size(&self) -> usize {
- match self {
- Master::Start => EbmlSize::Unknown.size(),
- Master::End => unreachable!(),
- Master::Collected(c) => {
- let mut size = 0;
- for c in c {
- size += c.size_full();
- }
- EbmlSize::Exact(size).size() + size
- }
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use crate::{Master, MatroskaTag, WriteValue};
-
- #[test]
- fn test_int_size() {
- let test = |x: i64| {
- eprintln!("{x:?}");
- let mut out = Vec::new();
- x.write_to(&mut out).unwrap();
- assert_eq!(out.len(), x.size())
- };
- test(1);
- test(2);
- test(20);
- test(200);
- test(2000);
- test(20000);
- test(200000);
- }
-
- #[test]
- fn test_uint_size() {
- let test = |x: u64| {
- eprintln!("{x:?}");
- let mut out = Vec::new();
- x.write_to(&mut out).unwrap();
- assert_eq!(out.len(), x.size())
- };
- test(1);
- test(2);
- test(20);
- test(200);
- test(2000);
- test(20000);
- test(200000);
- }
-
- #[test]
- fn test_string_size() {
- let test = |x: &str| {
- eprintln!("{x:?}");
- let x = x.to_owned();
- let mut out = Vec::new();
- x.write_to(&mut out).unwrap();
- assert_eq!(out.len(), x.size())
- };
- test("");
- test("x");
- test("wub");
- test("Hello world");
- test("just making sure that");
- test("this is actually working *exactly* how i want it to");
- test("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
- }
-
- #[test]
- fn test_vec_size() {
- let test = |x: &[u8]| {
- eprintln!("{x:?}");
- let x = x.to_owned();
- let mut out = Vec::new();
- x.write_to(&mut out).unwrap();
- assert_eq!(out.len(), x.size())
- };
- test(&[]);
- test(&[1]);
- test(&[1, 2]);
- test(&[23, 4, 4, 23, 4, 234, 232, 4, 234, 23, 1]);
- test(&[
- 34, 123, 5, 1, 3, 13, 1, 23, 12, 5, 5, 3, 123, 12, 3, 13, 12, 5, 3, 123, 13, 1, 3,
- ]);
- }
-
- #[test]
- fn test_master_size() {
- let test = |x: Master| {
- eprintln!("{x:?}");
- let x = x.to_owned();
- let mut out = Vec::new();
- x.write_to(&mut out).unwrap();
- assert_eq!(out.len(), x.size())
- };
- test(Master::Start);
- // test(Master::End);
- test(Master::Collected(vec![]));
- test(Master::Collected(vec![MatroskaTag::EbmlVersion(1)]));
- test(Master::Collected(vec![
- MatroskaTag::EbmlVersion(1),
- MatroskaTag::EbmlMaxSizeLength(4),
- MatroskaTag::EbmlReadVersion(3),
- MatroskaTag::EbmlMaxIdLength(4),
- ]));
- }
-}