Add PrintableString utility

Strings defined by third parties may contain control characters. Provide
a wrapper such that these are replaced when displayed. Useful in node
aliases and offer fields.
This commit is contained in:
Jeffrey Czyz 2022-10-06 13:44:35 -05:00
parent 50aeee5afb
commit 48bb9edba1
No known key found for this signature in database
GPG key ID: 912EF12EA67705F5
3 changed files with 47 additions and 10 deletions

View file

@ -31,6 +31,7 @@ use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer, MaybeReadable}
use crate::util::logger::{Logger, Level};
use crate::util::events::{Event, EventHandler, MessageSendEvent, MessageSendEventsProvider};
use crate::util::scid_utils::{block_from_scid, scid_from_parts, MAX_SCID_BLOCK};
use crate::util::string::PrintableString;
use crate::io;
use crate::io_extras::{copy, sink};
@ -1022,23 +1023,17 @@ pub struct NodeAlias(pub [u8; 32]);
impl fmt::Display for NodeAlias {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let control_symbol = core::char::REPLACEMENT_CHARACTER;
let first_null = self.0.iter().position(|b| *b == 0).unwrap_or(self.0.len());
let bytes = self.0.split_at(first_null).0;
match core::str::from_utf8(bytes) {
Ok(alias) => {
for c in alias.chars() {
let mut bytes = [0u8; 4];
let c = if !c.is_control() { c } else { control_symbol };
f.write_str(c.encode_utf8(&mut bytes))?;
}
},
Ok(alias) => PrintableString(alias).fmt(f)?,
Err(_) => {
use core::fmt::Write;
for c in bytes.iter().map(|b| *b as char) {
// Display printable ASCII characters
let mut bytes = [0u8; 4];
let control_symbol = core::char::REPLACEMENT_CHARACTER;
let c = if c >= '\x20' && c <= '\x7e' { c } else { control_symbol };
f.write_str(c.encode_utf8(&mut bytes))?;
f.write_char(c)?;
}
},
};

View file

@ -21,6 +21,7 @@ pub mod ser;
pub mod message_signing;
pub mod invoice;
pub mod persist;
pub mod string;
pub mod wakers;
pub(crate) mod atomic_counter;

View file

@ -0,0 +1,41 @@
// This file is Copyright its original authors, visible in version control
// history.
//
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
// You may not use this file except in accordance with one or both of these
// licenses.
//! Utilities for strings.
use core::fmt;
/// A string that displays only printable characters, replacing control characters with
/// [`core::char::REPLACEMENT_CHARACTER`].
pub struct PrintableString<'a>(pub &'a str);
impl<'a> fmt::Display for PrintableString<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
use core::fmt::Write;
for c in self.0.chars() {
let c = if c.is_control() { core::char::REPLACEMENT_CHARACTER } else { c };
f.write_char(c)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::PrintableString;
#[test]
fn displays_printable_string() {
assert_eq!(
format!("{}", PrintableString("I \u{1F496} LDK!\t\u{26A1}")),
"I \u{1F496} LDK!\u{FFFD}\u{26A1}",
);
}
}