Skip to content

Commit 6e33ca6

Browse files
committed
ogg_pager: Restrict page sizes to 8KB; Fix segment table generation when paginating
1 parent 9c69f00 commit 6e33ca6

File tree

1 file changed

+41
-28
lines changed

1 file changed

+41
-28
lines changed

ogg_pager/src/paginate.rs

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use crate::error::Result;
22
use crate::{
33
segment_table, Page, PageHeader, CONTAINS_FIRST_PAGE_OF_BITSTREAM,
4-
CONTAINS_LAST_PAGE_OF_BITSTREAM, CONTINUED_PACKET, MAX_CONTENT_SIZE,
4+
CONTAINS_LAST_PAGE_OF_BITSTREAM, CONTINUED_PACKET, MAX_WRITTEN_CONTENT_SIZE,
5+
MAX_WRITTEN_SEGMENT_COUNT,
56
};
67

78
use std::io::Read;
@@ -33,13 +34,13 @@ impl PaginateContext {
3334
},
3435
pos: 0,
3536
idx: 0,
36-
remaining_page_size: MAX_CONTENT_SIZE,
37+
remaining_page_size: MAX_WRITTEN_CONTENT_SIZE,
3738
current_packet_len: 0,
3839
}
3940
}
4041

41-
fn flush(&mut self, content: &mut Vec<u8>, segments: &mut Vec<u8>) {
42-
let header = PageHeader {
42+
fn flush(&mut self, content: &mut Vec<u8>, segment_table: &mut Vec<u8>) {
43+
let mut header = PageHeader {
4344
start: self.pos,
4445
header_type_flag: {
4546
match self.flags.first_page {
@@ -60,31 +61,44 @@ impl PaginateContext {
6061
},
6162
stream_serial: self.stream_serial,
6263
sequence_number: self.idx as u32,
64+
segments: Vec::new(),
6365
// No need to calculate this yet
6466
checksum: 0,
6567
};
6668

6769
let content = core::mem::take(content);
68-
let segments = core::mem::take(segments);
69-
7070
let content_len = content.len();
7171
self.pos += content_len as u64;
7272

73+
// Moving on to a new packet
74+
if self.pos > self.current_packet_len as u64 {
75+
self.flags.packet_spans_multiple_pages = false;
76+
}
77+
78+
// We need to determine how many segments our page content takes up.
79+
// If it takes up the remainder of the segment table for the entire packet,
80+
// we'll just consume it as is.
81+
let segments_occupied = if content_len >= 255 {
82+
content_len / 255
83+
} else {
84+
1
85+
};
86+
87+
if self.flags.packet_spans_multiple_pages {
88+
header.segments = segment_table.drain(..segments_occupied).collect();
89+
} else {
90+
header.segments = core::mem::take(segment_table);
91+
}
92+
7393
self.pages.push(Page {
7494
content,
75-
segments,
7695
header,
7796
end: self.pos,
7897
});
7998

8099
self.idx += 1;
81100
self.flags.packet_finished_on_page = false;
82-
self.remaining_page_size = MAX_CONTENT_SIZE;
83-
84-
// Moving on to a new packet
85-
if self.pos > self.current_packet_len as u64 {
86-
self.flags.packet_spans_multiple_pages = false;
87-
}
101+
self.remaining_page_size = MAX_WRITTEN_CONTENT_SIZE;
88102
}
89103
}
90104

@@ -117,8 +131,6 @@ pub fn paginate<'a, I: 'a>(
117131
where
118132
I: IntoIterator<Item = &'a [u8]>,
119133
{
120-
const MAX_SEGMENT_COUNT: usize = 255;
121-
122134
let mut ctx = PaginateContext::new(abgp, stream_serial, flags);
123135

124136
let mut packets_iter = packets.into_iter();
@@ -129,14 +141,15 @@ where
129141
};
130142
ctx.current_packet_len = packet.len();
131143

132-
let mut segments = Vec::with_capacity(255);
144+
let mut segments = segment_table(packet.len());
133145
let mut page_content = Vec::new();
134146

135147
loop {
136148
if !ctx.flags.packet_spans_multiple_pages && !ctx.flags.first_page {
137149
match packets_iter.next() {
138150
Some(packet_) => {
139151
packet = packet_;
152+
segments.append(&mut segment_table(packet.len()));
140153
ctx.current_packet_len = packet.len();
141154
ctx.flags.fresh_packet = true;
142155
},
@@ -150,30 +163,30 @@ where
150163
.take(ctx.remaining_page_size as u64)
151164
.read_to_end(&mut page_content)?;
152165
ctx.remaining_page_size -= bytes_read;
153-
packet = &packet[bytes_read..];
154-
155-
segments.append(&mut segment_table(bytes_read)?);
156-
let remaining_segments = MAX_SEGMENT_COUNT - segments.len();
157-
158-
// We have a maximum of 255 segments available per page, if we require more than
159-
// is left in the segment table, we'll have to split the packet into multiple pages.
160-
let segments_required = (packet.len() / 255) + 1;
161-
ctx.flags.packet_spans_multiple_pages = segments_required > remaining_segments;
162166

167+
packet = &packet[bytes_read..];
163168
// We need to indicate whether or not any packet was finished on this page.
164169
// This is used for the absolute granule position.
165170
if packet.is_empty() {
166171
ctx.flags.packet_finished_on_page = true;
167172
}
168173

169174
// The first packet of the bitstream must have its own page, unlike any other packet.
170-
let first_packet_finished_on_page = ctx.flags.first_page
171-
&& ctx.header_flags & CONTAINS_FIRST_PAGE_OF_BITSTREAM != 0
172-
&& ctx.flags.packet_finished_on_page;
175+
let first_page_of_bitstream = ctx.header_flags & CONTAINS_FIRST_PAGE_OF_BITSTREAM != 0;
176+
let first_packet_finished_on_page =
177+
ctx.flags.first_page && first_page_of_bitstream && ctx.flags.packet_finished_on_page;
178+
179+
// We have a maximum of `MAX_WRITTEN_SEGMENT_COUNT` segments available per page, if we require more than
180+
// is left in the segment table, we'll have to split the packet into multiple pages.
181+
let segments_required = (packet.len() / MAX_WRITTEN_SEGMENT_COUNT) + 1;
182+
let remaining_segments = MAX_WRITTEN_SEGMENT_COUNT.saturating_sub(segments.len());
183+
ctx.flags.packet_spans_multiple_pages = segments_required > remaining_segments;
173184

174185
if first_packet_finished_on_page
175186
// We've completely filled this page, we need to flush before moving on
176187
|| (ctx.remaining_page_size == 0 || remaining_segments == 0)
188+
// We've read all this packet has to offer
189+
|| packet.is_empty()
177190
{
178191
ctx.flush(&mut page_content, &mut segments);
179192
}

0 commit comments

Comments
 (0)