///|
fn pdf_pagespec_range(start : Int, finish : Int) -> Array[Int] {
let output : Array[Int] = Array::new(
capacity=if start <= finish {
finish - start + 1
} else {
start - finish + 1
},
)
if start <= finish {
let mut page = start
while page <= finish {
output.push(page)
page += 1
}
} else {
let mut page = start
while page >= finish {
output.push(page)
page -= 1
}
}
output
}
///|
fn pdf_pagespec_all_pages(end_page : Int) -> Array[Int] {
pdf_pagespec_range(1, end_page)
}
///|
fn pdf_pagespec_invert_range(
end_page : Int,
range : ArrayView[Int],
) -> Array[Int] {
if end_page <= 0 {
[]
} else {
let selected_pages = Array::make(end_page + 1, false)
for selected in range {
if selected >= 1 && selected <= end_page {
selected_pages[selected] = true
}
}
let output : Array[Int] = Array::new(capacity=end_page)
for page in 1..<=end_page {
if !selected_pages[page] {
output.push(page)
}
}
output
}
}
///|
fn pdf_pagespec_count_commas(tokens : ArrayView[PdfPageSpecToken]) -> Int {
let mut count = 0
for token in tokens {
if token is PageSpecComma {
count += 1
}
}
count
}
///|
fn pdf_pagespec_sum_lengths(parts : ArrayView[Array[Int]]) -> Int {
let mut length = 0
for part in parts {
length += part.length()
}
length
}
///|
fn pdf_pagespec_flatten(parts : ArrayView[Array[Int]]) -> Array[Int] {
let output : Array[Int] = Array::new(capacity=pdf_pagespec_sum_lengths(parts))
for part in parts {
for page in part {
output.push(page)
}
}
output
}
///|
/// Return pages in `1..=end_page` that are not present in `range`.
pub fn pdf_invert_page_range(
end_page : Int,
range : ArrayView[Int],
) -> Array[Int] {
pdf_pagespec_invert_range(end_page, range)
}
///|
/// Source-spelled compatibility alias for cpdfpagespec's `invert_range`.
pub fn pdf_invert_range(end_page : Int, range : ArrayView[Int]) -> Array[Int] {
pdf_pagespec_invert_range(end_page, range)
}
///|
fn pdf_pagespec_duplicate_range(
count : Int,
range : ArrayView[Int],
) -> Array[Int] {
let output : Array[Int] = Array::new(capacity=count * range.length())
for page in range {
for _ in 0.. Array[Int] {
let output : Array[Int] = Array::new(capacity=range.length())
for page in range {
if page % 2 != 0 {
output.push(page)
}
}
output
}
///|
fn pdf_pagespec_filter_even(range : ArrayView[Int]) -> Array[Int] {
let output : Array[Int] = Array::new(capacity=range.length())
for page in range {
if page % 2 == 0 {
output.push(page)
}
}
output
}
///|
fn pdf_pagespec_token_number(
context : PdfPageSpecContext,
token : PdfPageSpecToken,
) -> Int? raise PdfError {
match token {
PageSpecNumber(value) => Some(value)
PageSpecWord("end") => Some(context.end_page)
PageSpecWord(text) if text.has_prefix("~") => {
let rest = text.unsafe_substring(start=1, end=text.length())
match pdf_pagespec_parse_nonnegative_int(rest) {
Some(value) => Some(context.end_page + 1 - value)
None => {
context.bad()
None
}
}
}
_ => None
}
}
///|
fn pdf_pagespec_split_commas(
tokens : ArrayView[PdfPageSpecToken],
context : PdfPageSpecContext,
comma_count : Int,
) -> Array[Array[PdfPageSpecToken]] raise PdfError {
let parts : Array[Array[PdfPageSpecToken]] = Array::new(
capacity=comma_count + 1,
)
let mut current : Array[PdfPageSpecToken] = Array::new(
capacity=tokens.length(),
)
for token in tokens {
if token is PageSpecComma {
if current.length() == 0 {
context.bad()
}
parts.push(current)
current = Array::new(capacity=tokens.length())
} else {
current.push(token)
}
}
if current.length() == 0 {
context.bad()
}
parts.push(current)
parts
}