///|
pub(all) suberror PackageError {
InvalidPackage(String)
MissingPart(String)
InvalidTextPart(String)
} derive(Debug, Eq)
///|
pub fn PackageError::to_string(self : PackageError) -> String {
match self {
InvalidPackage(message) => "invalid package: " + message
MissingPart(name) => "missing package part: " + name
InvalidTextPart(name) => "package part is not valid UTF-8: " + name
}
}
///|
pub(all) struct Part {
name : String
content : FixedArray[Byte]
} derive(Debug, Eq)
///|
pub(all) struct Relationship {
id : String
relationship_type : String
target : String
external : Bool
} derive(Debug, Eq)
///|
pub(all) struct Package {
parts : Array[Part]
} derive(Debug, Eq)
///|
pub fn Package::part(self : Package, name : String) -> Part? {
let normalized = normalize_part_name(name)
for part in self.parts {
if part.name == normalized {
return Some(part)
}
}
None
}
///|
pub fn Package::has_part(self : Package, name : String) -> Bool {
self.part(name) is Some(_)
}
///|
pub fn Package::text(
self : Package,
name : String,
) -> String raise PackageError {
match self.part(name) {
Some(part) =>
@fzip.str_from_u8(part.content) catch {
_ => raise PackageError::InvalidTextPart(name)
}
None => raise PackageError::MissingPart(name)
}
}
///|
pub fn Package::replace_text(
self : Package,
name : String,
content : String,
) -> Package {
self.replace_part(name, @utf8.encode(content).to_fixedarray())
}
///|
pub fn Package::replace_part(
self : Package,
name : String,
content : FixedArray[Byte],
) -> Package {
let normalized = normalize_part_name(name)
let parts = []
let replaced = Ref(false)
for part in self.parts {
if part.name == normalized {
parts.push({ name: normalized, content })
replaced.val = true
} else {
parts.push(part)
}
}
if !replaced.val {
parts.push({ name: normalized, content })
}
{ parts, }
}
///|
pub fn Package::relationships(
self : Package,
source_part : String,
) -> Array[Relationship] raise PackageError {
parse_relationships(self.text(relationships_part_name(source_part)))
}
///|
pub fn open(content : FixedArray[Byte]) -> Package raise PackageError {
open_package_with_policy(content, ArchivePolicy::default())
}
///|
/// Open an OPC package using explicit, validated per-open archive limits.
///
/// ZIP central-directory metadata is checked before extraction, CRC
/// verification is mandatory, and declared sizes are compared with extracted
/// outputs before the package is returned.
pub fn open_with_policy(
content : FixedArray[Byte],
policy : ArchivePolicy,
) -> Package raise PackageError {
open_package_with_policy(content, policy)
}
///|
pub fn save(archive : Package) -> FixedArray[Byte] raise PackageError {
save_package(archive)
}