///|
pub fn string_to_utf8_bytes(str : String) -> Array[Byte] {
let bytes : Array[Byte] = []
let len = str.length()
let mut i = 0
while i < len {
let u = str.at(i).to_int()
let mut cp = u
if u >= 0xD800 && u <= 0xDBFF && i + 1 < len {
let low = str.at(i + 1).to_int()
if low >= 0xDC00 && low <= 0xDFFF {
cp = 0x10000 + ((u - 0xD800) << 10) + (low - 0xDC00)
i = i + 1
}
}
if cp <= 0x7F {
bytes.push(cp.to_byte())
} else if cp <= 0x7FF {
bytes.push(((cp >> 6) | 0xC0).to_byte())
bytes.push(((cp & 0x3F) | 0x80).to_byte())
} else if cp <= 0xFFFF {
bytes.push(((cp >> 12) | 0xE0).to_byte())
bytes.push((((cp >> 6) & 0x3F) | 0x80).to_byte())
bytes.push(((cp & 0x3F) | 0x80).to_byte())
} else {
bytes.push(((cp >> 18) | 0xF0).to_byte())
bytes.push((((cp >> 12) & 0x3F) | 0x80).to_byte())
bytes.push((((cp >> 6) & 0x3F) | 0x80).to_byte())
bytes.push(((cp & 0x3F) | 0x80).to_byte())
}
i = i + 1
}
bytes
}
///|
pub fn utf8_bytes_to_string(bytes : Array[Byte]) -> String? {
let builder = StringBuilder::StringBuilder()
let len = bytes.length()
let mut i = 0
while i < len {
let b0 = bytes[i].to_int()
if b0 <= 0x7F {
let ch = match b0.to_char() {
Some(c) => c
None => return None
}
builder.write_char(ch)
i = i + 1
} else if b0 >= 0xC2 && b0 <= 0xDF {
if i + 1 >= len {
return None
}
let b1 = bytes[i + 1].to_int()
if (b1 & 0xC0) != 0x80 {
return None
}
let cp = ((b0 & 0x1F) << 6) | (b1 & 0x3F)
let ch = match cp.to_char() {
Some(c) => c
None => return None
}
builder.write_char(ch)
i = i + 2
} else if b0 >= 0xE0 && b0 <= 0xEF {
if i + 2 >= len {
return None
}
let b1 = bytes[i + 1].to_int()
let b2 = bytes[i + 2].to_int()
if (b1 & 0xC0) != 0x80 || (b2 & 0xC0) != 0x80 {
return None
}
if b0 == 0xE0 && b1 < 0xA0 {
return None // overlong
}
if b0 == 0xED && b1 >= 0xA0 {
return None // surrogate
}
let cp = ((b0 & 0x0F) << 12) | ((b1 & 0x3F) << 6) | (b2 & 0x3F)
let ch = match cp.to_char() {
Some(c) => c
None => return None
}
builder.write_char(ch)
i = i + 3
} else if b0 >= 0xF0 && b0 <= 0xF4 {
if i + 3 >= len {
return None
}
let b1 = bytes[i + 1].to_int()
let b2 = bytes[i + 2].to_int()
let b3 = bytes[i + 3].to_int()
if (b1 & 0xC0) != 0x80 || (b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 {
return None
}
if b0 == 0xF0 && b1 < 0x90 {
return None // overlong
}
if b0 == 0xF4 && b1 > 0x8F {
return None // > 0x10FFFF
}
let cp = ((b0 & 0x07) << 18) |
((b1 & 0x3F) << 12) |
((b2 & 0x3F) << 6) |
(b3 & 0x3F)
let ch = match cp.to_char() {
Some(c) => c
None => return None
}
builder.write_char(ch)
i = i + 4
} else {
return None
}
}
Some(builder.to_string())
}