///|
pub fn render_calendar(calendar : Calendar) -> String {
let b = StringBuilder::new()
b.write_string("BEGIN:VCALENDAR\r\n")
for prop in calendar.properties {
b.write_string(fold_line(render_property(prop)))
b.write_string("\r\n")
}
for component in calendar.components {
render_component(component, b)
}
b.write_string("END:VCALENDAR\r\n")
b.to_string()
}
///|
fn render_component(component : Component, b : StringBuilder) -> Unit {
b.write_string("BEGIN:")
b.write_string(component.name)
b.write_string("\r\n")
for prop in component.properties {
b.write_string(fold_line(render_property(prop)))
b.write_string("\r\n")
}
for child in component.components {
render_component(child, b)
}
b.write_string("END:")
b.write_string(component.name)
b.write_string("\r\n")
}
///|
pub fn render_property(prop : Property) -> String {
let b = StringBuilder::new()
b.write_string(prop.name)
for param in prop.params {
b.write_string(";")
b.write_string(param.name)
b.write_string("=")
let mut first = true
for value in param.values {
if first {
first = false
} else {
b.write_string(",")
}
b.write_string(render_param_value(value))
}
}
b.write_string(":")
if prop.name == "SUMMARY" ||
prop.name == "DESCRIPTION" ||
prop.name == "LOCATION" {
b.write_string(escape_text(unescape_text(prop.value)))
} else {
b.write_string(prop.value)
}
b.to_string()
}
///|
fn render_param_value(value : String) -> String {
let mut needs_quotes = false
let mut i = 0
while i < value.length() {
let code = value[i]
if code == 44 || code == 59 || code == 58 || code == 34 {
needs_quotes = true
}
i += 1
}
if !needs_quotes {
return value
}
let b = StringBuilder::new()
b.write_string("\"")
i = 0
while i < value.length() {
let code = value[i]
if code == 34 {
b.write_string("\\\"")
} else {
b.write_char(code.unsafe_to_char())
}
i += 1
}
b.write_string("\"")
b.to_string()
}
///|
pub fn fold_line(line : String) -> String {
if line.length() <= 73 {
return line
}
let b = StringBuilder::new()
let mut start = 0
while start < line.length() {
let end = if start + 73 < line.length() {
start + 73
} else {
line.length()
}
if start != 0 {
b.write_string("\r\n ")
}
b.write_string(line[start:end].to_owned())
start = end
}
b.to_string()
}
///|
pub fn render_validation(report : ValidationReport) -> String {
let b = StringBuilder::new()
b.write_string("# MoonCalGuard validation\n\n")
b.write_string("- accepted: ")
b.write_string(report.accepted.to_string())
b.write_string("\n- findings: ")
b.write_string(report.findings.length().to_string())
b.write_string("\n\n")
for finding in report.findings {
b.write_string("- [")
b.write_string(finding.severity.name())
b.write_string("] ")
b.write_string(finding.code)
b.write_string(": ")
b.write_string(finding.message)
b.write_string("\n")
}
b.to_string()
}