const OGG_CRC_TABLE: [u32; 256] = {
let mut t = [0u32; 256];
let mut i = 0usize;
while i < 256 {
let mut crc = (i as u32) << 24;
let mut j = 0;
while j < 8 {
crc = if crc & 0x8000_0000 != 0 {
(crc << 1) ^ 0x04c1_1db7
} else {
crc << 1
};
j += 1;
}
t[i] = crc;
i += 1;
}
t
};
fn crc_update(mut crc: u32, bytes: &[u8]) -> u32 {
for &b in bytes {
crc = (crc << 8) ^ OGG_CRC_TABLE[(((crc >> 24) & 0xff) as u8 ^ b) as usize];
}
crc
}
pub struct OggStream {
body: Vec<u8>,
body_returned: usize,
lacing: Vec<i32>,
granule: Vec<i64>,
granulepos: i64,
pageno: i64,
began: bool,
e_o_s: bool,
serialno: i32,
out: Vec<u8>,
}
impl OggStream {
pub fn new(serialno: i32) -> Self {
Self {
body: Vec::new(),
body_returned: 0,
lacing: Vec::new(),
granule: Vec::new(),
granulepos: 0,
pageno: 0,
began: false,
e_o_s: false,
serialno,
out: Vec::new(),
}
}
pub fn packetin(&mut self, packet: &[u8], e_o_s: bool, granulepos: i64) {
let bytes = packet.len();
let lacing_count = bytes / 255 + 1;
self.body.extend_from_slice(packet);
let first = self.lacing.len();
for _ in 0..lacing_count - 1 {
self.lacing.push(255);
self.granule.push(self.granulepos);
}
self.lacing.push((bytes % 255) as i32);
self.granule.push(granulepos);
self.granulepos = granulepos;
self.lacing[first] |= 0x100;
if e_o_s {
self.e_o_s = true;
}
}
fn flush_i(&mut self, mut force: bool, nfill: i64) -> bool {
let lacing_fill = self.lacing.len();
let maxvals = lacing_fill.min(255);
if maxvals == 0 {
return false;
}
let mut vals = 0usize;
let granule_pos: i64;
if !self.began {
granule_pos = 0;
while vals < maxvals {
let end = (self.lacing[vals] & 0xff) < 255;
vals += 1;
if end {
break;
}
}
} else {
let mut acc = 0i64;
let mut packets_done = 0;
let mut packet_just_done = 0;
let mut gp = -1i64;
while vals < maxvals {
if acc > nfill && packet_just_done >= 4 {
force = true;
break;
}
acc += (self.lacing[vals] & 0xff) as i64;
if (self.lacing[vals] & 0xff) < 255 {
gp = self.granule[vals];
packets_done += 1;
packet_just_done = packets_done;
} else {
packet_just_done = 0;
}
vals += 1;
}
if vals == 255 {
force = true;
}
granule_pos = gp;
}
if !force {
return false;
}
let mut header = Vec::with_capacity(27 + vals);
header.extend_from_slice(b"OggS");
header.push(0x00); let mut flags = 0u8;
if self.lacing[0] & 0x100 == 0 {
flags |= 0x01; }
if !self.began {
flags |= 0x02; }
if self.e_o_s && lacing_fill == vals {
flags |= 0x04; }
header.push(flags);
self.began = true;
let mut g = granule_pos as u64;
for _ in 0..8 {
header.push((g & 0xff) as u8);
g >>= 8;
}
let mut s = self.serialno as u32;
for _ in 0..4 {
header.push((s & 0xff) as u8);
s >>= 8;
}
let mut p = self.pageno as u64;
self.pageno += 1;
for _ in 0..4 {
header.push((p & 0xff) as u8);
p >>= 8;
}
header.extend_from_slice(&[0, 0, 0, 0]);
header.push(vals as u8);
let mut body_len = 0usize;
for i in 0..vals {
let lv = (self.lacing[i] & 0xff) as u8;
header.push(lv);
body_len += lv as usize;
}
let body = &self.body[self.body_returned..self.body_returned + body_len];
let crc = crc_update(crc_update(0, &header), body);
header[22] = (crc & 0xff) as u8;
header[23] = ((crc >> 8) & 0xff) as u8;
header[24] = ((crc >> 16) & 0xff) as u8;
header[25] = ((crc >> 24) & 0xff) as u8;
self.out.extend_from_slice(&header);
self.out.extend_from_slice(body);
self.body_returned += body_len;
self.lacing.drain(0..vals);
self.granule.drain(0..vals);
true
}
pub fn flush(&mut self) {
while self.flush_i(true, 4096) {}
}
pub fn pageout(&mut self) {
loop {
let force =
(self.e_o_s && !self.lacing.is_empty()) || (!self.lacing.is_empty() && !self.began);
if !self.flush_i(force, 4096) {
break;
}
}
}
pub fn into_bytes(self) -> Vec<u8> {
self.out
}
}
pub fn read_packets(data: &[u8]) -> Option<Vec<Vec<u8>>> {
let mut packets = Vec::new();
let mut cur: Vec<u8> = Vec::new();
let mut pos = 0usize;
while pos < data.len() {
if pos + 27 > data.len() || &data[pos..pos + 4] != b"OggS" {
return None;
}
let nsegs = data[pos + 26] as usize;
let seg_table = pos + 27;
let body_start = seg_table + nsegs;
if body_start > data.len() {
return None;
}
let body_len: usize = data[seg_table..body_start]
.iter()
.map(|&b| b as usize)
.sum();
let body_end = body_start + body_len;
if body_end > data.len() {
return None;
}
let stored = u32::from_le_bytes([
data[pos + 22],
data[pos + 23],
data[pos + 24],
data[pos + 25],
]);
let mut header = data[pos..body_start].to_vec();
header[22] = 0;
header[23] = 0;
header[24] = 0;
header[25] = 0;
if crc_update(crc_update(0, &header), &data[body_start..body_end]) != stored {
return None;
}
let mut boff = body_start;
for i in 0..nsegs {
let lv = data[seg_table + i] as usize;
cur.extend_from_slice(&data[boff..boff + lv]);
boff += lv;
if lv < 255 {
packets.push(std::mem::take(&mut cur));
}
}
pos = body_end;
}
Some(packets)
}