@@ -83,7 +83,7 @@ impl fmt::Display for DataType {
8383impl DataType {
8484 pub fn display_labels ( & self , endian : object:: Endianness , bytes : & [ u8 ] ) -> Vec < String > {
8585 let mut strs = Vec :: new ( ) ;
86- for ( literal, label_override) in self . display_literals ( endian, bytes) {
86+ for ( literal, label_override, _ ) in self . display_literals ( endian, bytes) {
8787 let label = label_override. unwrap_or_else ( || self . to_string ( ) ) ;
8888 strs. push ( format ! ( "{label}: {literal:?}" ) )
8989 }
@@ -94,7 +94,7 @@ impl DataType {
9494 & self ,
9595 endian : object:: Endianness ,
9696 bytes : & [ u8 ] ,
97- ) -> Vec < ( String , Option < String > ) > {
97+ ) -> Vec < ( String , Option < String > , Option < String > ) > {
9898 let mut strs = Vec :: new ( ) ;
9999 if self . required_len ( ) . is_some_and ( |l| bytes. len ( ) < l) {
100100 log:: warn!(
@@ -118,34 +118,34 @@ impl DataType {
118118 match self {
119119 DataType :: Int8 => {
120120 let i = i8:: from_ne_bytes ( bytes. try_into ( ) . unwrap ( ) ) ;
121- strs. push ( ( format ! ( "{i:#x}" ) , None ) ) ;
121+ strs. push ( ( format ! ( "{i:#x}" ) , None , None ) ) ;
122122
123123 if i < 0 {
124- strs. push ( ( format ! ( "{:#x}" , ReallySigned ( i) ) , None ) ) ;
124+ strs. push ( ( format ! ( "{:#x}" , ReallySigned ( i) ) , None , None ) ) ;
125125 }
126126 }
127127 DataType :: Int16 => {
128128 let i = endian. read_i16_bytes ( bytes. try_into ( ) . unwrap ( ) ) ;
129- strs. push ( ( format ! ( "{i:#x}" ) , None ) ) ;
129+ strs. push ( ( format ! ( "{i:#x}" ) , None , None ) ) ;
130130
131131 if i < 0 {
132- strs. push ( ( format ! ( "{:#x}" , ReallySigned ( i) ) , None ) ) ;
132+ strs. push ( ( format ! ( "{:#x}" , ReallySigned ( i) ) , None , None ) ) ;
133133 }
134134 }
135135 DataType :: Int32 => {
136136 let i = endian. read_i32_bytes ( bytes. try_into ( ) . unwrap ( ) ) ;
137- strs. push ( ( format ! ( "{i:#x}" ) , None ) ) ;
137+ strs. push ( ( format ! ( "{i:#x}" ) , None , None ) ) ;
138138
139139 if i < 0 {
140- strs. push ( ( format ! ( "{:#x}" , ReallySigned ( i) ) , None ) ) ;
140+ strs. push ( ( format ! ( "{:#x}" , ReallySigned ( i) ) , None , None ) ) ;
141141 }
142142 }
143143 DataType :: Int64 => {
144144 let i = endian. read_i64_bytes ( bytes. try_into ( ) . unwrap ( ) ) ;
145- strs. push ( ( format ! ( "{i:#x}" ) , None ) ) ;
145+ strs. push ( ( format ! ( "{i:#x}" ) , None , None ) ) ;
146146
147147 if i < 0 {
148- strs. push ( ( format ! ( "{:#x}" , ReallySigned ( i) ) , None ) ) ;
148+ strs. push ( ( format ! ( "{:#x}" , ReallySigned ( i) ) , None , None ) ) ;
149149 }
150150 }
151151 DataType :: Float => {
@@ -156,6 +156,7 @@ impl DataType {
156156 object:: Endianness :: Big => f32 :: from_be_bytes( bytes) ,
157157 } ) ,
158158 None ,
159+ None ,
159160 ) ) ;
160161 }
161162 DataType :: Double => {
@@ -166,24 +167,29 @@ impl DataType {
166167 object:: Endianness :: Big => f64 :: from_be_bytes( bytes) ,
167168 } ) ,
168169 None ,
170+ None ,
169171 ) ) ;
170172 }
171173 DataType :: Bytes => {
172- strs. push ( ( format ! ( "{bytes:#?}" ) , None ) ) ;
174+ strs. push ( ( format ! ( "{bytes:#?}" ) , None , None ) ) ;
173175 }
174176 DataType :: String => {
175177 if let Some ( nul_idx) = bytes. iter ( ) . position ( |& c| c == b'\0' ) {
176178 let str_bytes = & bytes[ ..nul_idx] ;
177179 // Special case to display (ASCII) as the label for ASCII-only strings.
178180 let ( cow, _, had_errors) = encoding_rs:: UTF_8 . decode ( str_bytes) ;
179181 if !had_errors && cow. is_ascii ( ) {
180- strs. push ( ( format ! ( "{cow}" ) , Some ( "ASCII" . into ( ) ) ) ) ;
182+ let string = format ! ( "{cow}" ) ;
183+ let copy_string = escape_special_ascii_characters ( string. clone ( ) ) ;
184+ strs. push ( ( string, Some ( "ASCII" . into ( ) ) , Some ( copy_string) ) ) ;
181185 }
182186 for ( encoding, encoding_name) in SUPPORTED_ENCODINGS {
183187 let ( cow, _, had_errors) = encoding. decode ( str_bytes) ;
184188 // Avoid showing ASCII-only strings more than once if the encoding is ASCII-compatible.
185189 if !had_errors && ( !encoding. is_ascii_compatible ( ) || !cow. is_ascii ( ) ) {
186- strs. push ( ( format ! ( "{cow}" ) , Some ( encoding_name. into ( ) ) ) ) ;
190+ let string = format ! ( "{cow}" ) ;
191+ let copy_string = escape_special_ascii_characters ( string. clone ( ) ) ;
192+ strs. push ( ( string, Some ( encoding_name. into ( ) ) , Some ( copy_string) ) ) ;
187193 }
188194 }
189195 }
@@ -499,3 +505,21 @@ pub struct RelocationOverride {
499505 pub target : RelocationOverrideTarget ,
500506 pub addend : i64 ,
501507}
508+
509+ /// Escape ASCII characters such as \n or \t, but not Unicode characters such as \u{3000}.
510+ /// Suitable for copying to clipboard.
511+ fn escape_special_ascii_characters ( value : String ) -> String {
512+ let mut escaped = String :: new ( ) ;
513+ escaped. push ( '"' ) ;
514+ for c in value. chars ( ) {
515+ if c. is_ascii ( ) {
516+ for e in c. escape_default ( ) {
517+ escaped. push ( e) ;
518+ }
519+ } else {
520+ escaped. push ( c) ;
521+ }
522+ }
523+ escaped. push ( '"' ) ;
524+ escaped
525+ }
0 commit comments