diff options
| -rw-r--r-- | src/zip/cp437.rs | 376 | ||||
| -rw-r--r-- | src/zip/driver.rs | 22 | ||||
| -rw-r--r-- | src/zip/error.rs | 2 | ||||
| -rw-r--r-- | src/zip/mod.rs | 1 | ||||
| -rw-r--r-- | src/zip/tests.rs | 34 |
5 files changed, 427 insertions, 8 deletions
diff --git a/src/zip/cp437.rs b/src/zip/cp437.rs new file mode 100644 index 0000000..e290ea6 --- /dev/null +++ b/src/zip/cp437.rs | |||
| @@ -0,0 +1,376 @@ | |||
| 1 | pub trait FromCp437<T>: Sized { | ||
| 2 | type Value; | ||
| 3 | |||
| 4 | fn from_cp437(value: T) -> Self::Value; | ||
| 5 | } | ||
| 6 | |||
| 7 | pub fn to_char(byte: u8) -> char { | ||
| 8 | char::from_u32(match byte { | ||
| 9 | 0..=127 => byte as u32, | ||
| 10 | 128 => 199, | ||
| 11 | 129 => 252, | ||
| 12 | 130 => 233, | ||
| 13 | 131 => 226, | ||
| 14 | 132 => 228, | ||
| 15 | 133 => 224, | ||
| 16 | 134 => 229, | ||
| 17 | 135 => 231, | ||
| 18 | 136 => 234, | ||
| 19 | 137 => 235, | ||
| 20 | 138 => 232, | ||
| 21 | 139 => 239, | ||
| 22 | 140 => 238, | ||
| 23 | 141 => 236, | ||
| 24 | 142 => 196, | ||
| 25 | 143 => 197, | ||
| 26 | 144 => 201, | ||
| 27 | 145 => 230, | ||
| 28 | 146 => 198, | ||
| 29 | 147 => 244, | ||
| 30 | 148 => 246, | ||
| 31 | 149 => 242, | ||
| 32 | 150 => 251, | ||
| 33 | 151 => 249, | ||
| 34 | 152 => 255, | ||
| 35 | 153 => 214, | ||
| 36 | 154 => 220, | ||
| 37 | 155 => 162, | ||
| 38 | 156 => 163, | ||
| 39 | 157 => 165, | ||
| 40 | 158 => 8359, | ||
| 41 | 159 => 402, | ||
| 42 | 160 => 225, | ||
| 43 | 161 => 237, | ||
| 44 | 162 => 243, | ||
| 45 | 163 => 250, | ||
| 46 | 164 => 241, | ||
| 47 | 165 => 209, | ||
| 48 | 166 => 170, | ||
| 49 | 167 => 186, | ||
| 50 | 168 => 191, | ||
| 51 | 169 => 8976, | ||
| 52 | 170 => 172, | ||
| 53 | 171 => 189, | ||
| 54 | 172 => 188, | ||
| 55 | 173 => 161, | ||
| 56 | 174 => 171, | ||
| 57 | 175 => 187, | ||
| 58 | 176 => 9617, | ||
| 59 | 177 => 9618, | ||
| 60 | 178 => 9619, | ||
| 61 | 179 => 9474, | ||
| 62 | 180 => 9508, | ||
| 63 | 181 => 9569, | ||
| 64 | 182 => 9570, | ||
| 65 | 183 => 9558, | ||
| 66 | 184 => 9557, | ||
| 67 | 185 => 9571, | ||
| 68 | 186 => 9553, | ||
| 69 | 187 => 9559, | ||
| 70 | 188 => 9565, | ||
| 71 | 189 => 9564, | ||
| 72 | 190 => 9563, | ||
| 73 | 191 => 9488, | ||
| 74 | 192 => 9492, | ||
| 75 | 193 => 9524, | ||
| 76 | 194 => 9516, | ||
| 77 | 195 => 9500, | ||
| 78 | 196 => 9472, | ||
| 79 | 197 => 9532, | ||
| 80 | 198 => 9566, | ||
| 81 | 199 => 9567, | ||
| 82 | 200 => 9562, | ||
| 83 | 201 => 9556, | ||
| 84 | 202 => 9577, | ||
| 85 | 203 => 9574, | ||
| 86 | 204 => 9568, | ||
| 87 | 205 => 9552, | ||
| 88 | 206 => 9580, | ||
| 89 | 207 => 9575, | ||
| 90 | 208 => 9576, | ||
| 91 | 209 => 9572, | ||
| 92 | 210 => 9573, | ||
| 93 | 211 => 9561, | ||
| 94 | 212 => 9560, | ||
| 95 | 213 => 9554, | ||
| 96 | 214 => 9555, | ||
| 97 | 215 => 9579, | ||
| 98 | 216 => 9578, | ||
| 99 | 217 => 9496, | ||
| 100 | 218 => 9484, | ||
| 101 | 219 => 9608, | ||
| 102 | 220 => 9604, | ||
| 103 | 221 => 9612, | ||
| 104 | 222 => 9616, | ||
| 105 | 223 => 9600, | ||
| 106 | 224 => 945, | ||
| 107 | 225 => 223, | ||
| 108 | 226 => 915, | ||
| 109 | 227 => 960, | ||
| 110 | 228 => 931, | ||
| 111 | 229 => 963, | ||
| 112 | 230 => 181, | ||
| 113 | 231 => 964, | ||
| 114 | 232 => 934, | ||
| 115 | 233 => 920, | ||
| 116 | 234 => 937, | ||
| 117 | 235 => 948, | ||
| 118 | 236 => 8734, | ||
| 119 | 237 => 966, | ||
| 120 | 238 => 949, | ||
| 121 | 239 => 8745, | ||
| 122 | 240 => 8801, | ||
| 123 | 241 => 177, | ||
| 124 | 242 => 8805, | ||
| 125 | 243 => 8804, | ||
| 126 | 244 => 8992, | ||
| 127 | 245 => 8993, | ||
| 128 | 246 => 247, | ||
| 129 | 247 => 8776, | ||
| 130 | 248 => 176, | ||
| 131 | 249 => 8729, | ||
| 132 | 250 => 183, | ||
| 133 | 251 => 8730, | ||
| 134 | 252 => 8319, | ||
| 135 | 253 => 178, | ||
| 136 | 254 => 9632, | ||
| 137 | 255 => 160, | ||
| 138 | }) | ||
| 139 | .unwrap() | ||
| 140 | } | ||
| 141 | |||
| 142 | pub fn from_char(char: char) -> Option<u8> { | ||
| 143 | Some(match char as u32 { | ||
| 144 | 0..=127 => char as u8, | ||
| 145 | 160 => 255, | ||
| 146 | 161 => 173, | ||
| 147 | 162 => 155, | ||
| 148 | 163 => 156, | ||
| 149 | 165 => 157, | ||
| 150 | 170 => 166, | ||
| 151 | 171 => 174, | ||
| 152 | 172 => 170, | ||
| 153 | 176 => 248, | ||
| 154 | 177 => 241, | ||
| 155 | 178 => 253, | ||
| 156 | 181 => 230, | ||
| 157 | 183 => 250, | ||
| 158 | 186 => 167, | ||
| 159 | 187 => 175, | ||
| 160 | 188 => 172, | ||
| 161 | 189 => 171, | ||
| 162 | 191 => 168, | ||
| 163 | 196 => 142, | ||
| 164 | 197 => 143, | ||
| 165 | 198 => 146, | ||
| 166 | 199 => 128, | ||
| 167 | 201 => 144, | ||
| 168 | 209 => 165, | ||
| 169 | 214 => 153, | ||
| 170 | 220 => 154, | ||
| 171 | 223 => 225, | ||
| 172 | 224 => 133, | ||
| 173 | 225 => 160, | ||
| 174 | 226 => 131, | ||
| 175 | 228 => 132, | ||
| 176 | 229 => 134, | ||
| 177 | 230 => 145, | ||
| 178 | 231 => 135, | ||
| 179 | 232 => 138, | ||
| 180 | 233 => 130, | ||
| 181 | 234 => 136, | ||
| 182 | 235 => 137, | ||
| 183 | 236 => 141, | ||
| 184 | 237 => 161, | ||
| 185 | 238 => 140, | ||
| 186 | 239 => 139, | ||
| 187 | 241 => 164, | ||
| 188 | 242 => 149, | ||
| 189 | 243 => 162, | ||
| 190 | 244 => 147, | ||
| 191 | 246 => 148, | ||
| 192 | 247 => 246, | ||
| 193 | 249 => 151, | ||
| 194 | 250 => 163, | ||
| 195 | 251 => 150, | ||
| 196 | 252 => 129, | ||
| 197 | 255 => 152, | ||
| 198 | 402 => 159, | ||
| 199 | 915 => 226, | ||
| 200 | 920 => 233, | ||
| 201 | 931 => 228, | ||
| 202 | 934 => 232, | ||
| 203 | 937 => 234, | ||
| 204 | 945 => 224, | ||
| 205 | 948 => 235, | ||
| 206 | 949 => 238, | ||
| 207 | 960 => 227, | ||
| 208 | 963 => 229, | ||
| 209 | 964 => 231, | ||
| 210 | 966 => 237, | ||
| 211 | 8319 => 252, | ||
| 212 | 8359 => 158, | ||
| 213 | 8729 => 249, | ||
| 214 | 8730 => 251, | ||
| 215 | 8734 => 236, | ||
| 216 | 8745 => 239, | ||
| 217 | 8776 => 247, | ||
| 218 | 8801 => 240, | ||
| 219 | 8804 => 243, | ||
| 220 | 8805 => 242, | ||
| 221 | 8976 => 169, | ||
| 222 | 8992 => 244, | ||
| 223 | 8993 => 245, | ||
| 224 | 9472 => 196, | ||
| 225 | 9474 => 179, | ||
| 226 | 9484 => 218, | ||
| 227 | 9488 => 191, | ||
| 228 | 9492 => 192, | ||
| 229 | 9496 => 217, | ||
| 230 | 9500 => 195, | ||
| 231 | 9508 => 180, | ||
| 232 | 9516 => 194, | ||
| 233 | 9524 => 193, | ||
| 234 | 9532 => 197, | ||
| 235 | 9552 => 205, | ||
| 236 | 9553 => 186, | ||
| 237 | 9554 => 213, | ||
| 238 | 9555 => 214, | ||
| 239 | 9556 => 201, | ||
| 240 | 9557 => 184, | ||
| 241 | 9558 => 183, | ||
| 242 | 9559 => 187, | ||
| 243 | 9560 => 212, | ||
| 244 | 9561 => 211, | ||
| 245 | 9562 => 200, | ||
| 246 | 9563 => 190, | ||
| 247 | 9564 => 189, | ||
| 248 | 9565 => 188, | ||
| 249 | 9566 => 198, | ||
| 250 | 9567 => 199, | ||
| 251 | 9568 => 204, | ||
| 252 | 9569 => 181, | ||
| 253 | 9570 => 182, | ||
| 254 | 9571 => 185, | ||
| 255 | 9572 => 209, | ||
| 256 | 9573 => 210, | ||
| 257 | 9574 => 203, | ||
| 258 | 9575 => 207, | ||
| 259 | 9576 => 208, | ||
| 260 | 9577 => 202, | ||
| 261 | 9578 => 216, | ||
| 262 | 9579 => 215, | ||
| 263 | 9580 => 206, | ||
| 264 | 9600 => 223, | ||
| 265 | 9604 => 220, | ||
| 266 | 9608 => 219, | ||
| 267 | 9612 => 221, | ||
| 268 | 9616 => 222, | ||
| 269 | 9617 => 176, | ||
| 270 | 9618 => 177, | ||
| 271 | 9619 => 178, | ||
| 272 | 9632 => 254, | ||
| 273 | _ => return None, | ||
| 274 | }) | ||
| 275 | } | ||
| 276 | |||
| 277 | pub fn is_cp437(char: char) -> bool { | ||
| 278 | match char as u32 { | ||
| 279 | 0..=127 => true, | ||
| 280 | 160..=163 => true, | ||
| 281 | 165 => true, | ||
| 282 | 170..=172 => true, | ||
| 283 | 176..=178 => true, | ||
| 284 | 181 => true, | ||
| 285 | 183 => true, | ||
| 286 | 186..=189 => true, | ||
| 287 | 191 => true, | ||
| 288 | 196..=199 => true, | ||
| 289 | 201 => true, | ||
| 290 | 209 => true, | ||
| 291 | 214 => true, | ||
| 292 | 220 => true, | ||
| 293 | 223..=226 => true, | ||
| 294 | 228..=239 => true, | ||
| 295 | 241..=244 => true, | ||
| 296 | 246..=247 => true, | ||
| 297 | 249..=252 => true, | ||
| 298 | 255 => true, | ||
| 299 | 402 => true, | ||
| 300 | 915 => true, | ||
| 301 | 920 => true, | ||
| 302 | 931 => true, | ||
| 303 | 934 => true, | ||
| 304 | 937 => true, | ||
| 305 | 945 => true, | ||
| 306 | 948..=949 => true, | ||
| 307 | 960 => true, | ||
| 308 | 963..=964 => true, | ||
| 309 | 966 => true, | ||
| 310 | 8319 => true, | ||
| 311 | 8359 => true, | ||
| 312 | 8729..=8730 => true, | ||
| 313 | 8734 => true, | ||
| 314 | 8745 => true, | ||
| 315 | 8776 => true, | ||
| 316 | 8801 => true, | ||
| 317 | 8804..=8805 => true, | ||
| 318 | 8976 => true, | ||
| 319 | 8992..=8993 => true, | ||
| 320 | 9472 => true, | ||
| 321 | 9474 => true, | ||
| 322 | 9484 => true, | ||
| 323 | 9488 => true, | ||
| 324 | 9492 => true, | ||
| 325 | 9496 => true, | ||
| 326 | 9500 => true, | ||
| 327 | 9508 => true, | ||
| 328 | 9516 => true, | ||
| 329 | 9524 => true, | ||
| 330 | 9532 => true, | ||
| 331 | 9552..=9580 => true, | ||
| 332 | 9600 => true, | ||
| 333 | 9604 => true, | ||
| 334 | 9608 => true, | ||
| 335 | 9612 => true, | ||
| 336 | 9616..=9619 => true, | ||
| 337 | 9632 => true, | ||
| 338 | _ => false, | ||
| 339 | } | ||
| 340 | } | ||
| 341 | |||
| 342 | impl FromCp437<Vec<u8>> for String { | ||
| 343 | type Value = Self; | ||
| 344 | |||
| 345 | fn from_cp437(bytes: Vec<u8>) -> Self { | ||
| 346 | Self::from_cp437(bytes.as_slice()) | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | impl<const S: usize> FromCp437<[u8; S]> for String { | ||
| 351 | type Value = Self; | ||
| 352 | |||
| 353 | fn from_cp437(bytes: [u8; S]) -> Self { | ||
| 354 | Self::from_cp437(bytes.as_slice()) | ||
| 355 | } | ||
| 356 | } | ||
| 357 | |||
| 358 | impl FromCp437<&[u8]> for String { | ||
| 359 | type Value = Self; | ||
| 360 | |||
| 361 | fn from_cp437(bytes: &[u8]) -> Self { | ||
| 362 | bytes.iter().copied().map(to_char).collect() | ||
| 363 | } | ||
| 364 | } | ||
| 365 | |||
| 366 | impl FromCp437<&str> for Vec<u8> { | ||
| 367 | type Value = Option<Self>; | ||
| 368 | |||
| 369 | fn from_cp437(text: &str) -> Option<Self> { | ||
| 370 | let mut bytes = Vec::with_capacity(text.chars().count()); | ||
| 371 | for c in text.chars() { | ||
| 372 | bytes.push(from_char(c)?); | ||
| 373 | } | ||
| 374 | Some(bytes) | ||
| 375 | } | ||
| 376 | } | ||
diff --git a/src/zip/driver.rs b/src/zip/driver.rs index 99b409d..4782e65 100644 --- a/src/zip/driver.rs +++ b/src/zip/driver.rs | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | use crate::driver::{ArchiveRead, ArchiveWrite, Driver}; | 1 | use crate::driver::{ArchiveRead, ArchiveWrite, Driver}; |
| 2 | use crate::utils::ReadUtils; | 2 | use crate::utils::ReadUtils; |
| 3 | use crate::zip::cp437::FromCp437; | ||
| 3 | use crate::zip::structs::{deserialize, Cdr, Eocdr, Eocdr64, Eocdr64Locator, ExtraHeader}; | 4 | use crate::zip::structs::{deserialize, Cdr, Eocdr, Eocdr64, Eocdr64Locator, ExtraHeader}; |
| 4 | use crate::zip::{ | 5 | use crate::zip::{ |
| 5 | BitFlag, CompressionMethod, ZipError, ZipFileInfo, ZipFileReader, ZipFileWriter, ZipResult, | 6 | BitFlag, CompressionMethod, ZipError, ZipFileInfo, ZipFileReader, ZipFileWriter, ZipResult, |
| @@ -77,7 +78,7 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> { | |||
| 77 | let comment = { | 78 | let comment = { |
| 78 | let mut buf: Vec<u8> = vec![0; eocdr.comment_len as usize]; | 79 | let mut buf: Vec<u8> = vec![0; eocdr.comment_len as usize]; |
| 79 | io.read(&mut buf)?; | 80 | io.read(&mut buf)?; |
| 80 | String::from_utf8(buf).map_err(|_| ZipError::InvalidArchiveComment)? | 81 | String::from_cp437(buf) |
| 81 | }; | 82 | }; |
| 82 | 83 | ||
| 83 | // Try to find eocdr64locator | 84 | // Try to find eocdr64locator |
| @@ -116,14 +117,23 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> { | |||
| 116 | } | 117 | } |
| 117 | p += 4; | 118 | p += 4; |
| 118 | let cdr: Cdr = deserialize(&buf[p..p + 42]).unwrap(); | 119 | let cdr: Cdr = deserialize(&buf[p..p + 42]).unwrap(); |
| 120 | let bit_flag = BitFlag::new(cdr.bit_flag); | ||
| 119 | p += 42; | 121 | p += 42; |
| 120 | let name = String::from_utf8(buf[p..p + cdr.name_len as usize].into()) | 122 | let name = if bit_flag.is_utf8() { |
| 121 | .map_err(|_| ZipError::InvalidFileName)?; | 123 | String::from_utf8(buf[p..p + cdr.name_len as usize].to_vec()) |
| 124 | .map_err(|_| ZipError::InvalidFileName)? | ||
| 125 | } else { | ||
| 126 | String::from_cp437(&buf[p..p + cdr.name_len as usize]) | ||
| 127 | }; | ||
| 122 | p += cdr.name_len as usize; | 128 | p += cdr.name_len as usize; |
| 123 | let extra_fields: Vec<u8> = buf[p..p + cdr.extra_field_len as usize].into(); | 129 | let extra_fields: Vec<u8> = buf[p..p + cdr.extra_field_len as usize].into(); |
| 124 | p += cdr.extra_field_len as usize; | 130 | p += cdr.extra_field_len as usize; |
| 125 | let comment = String::from_utf8(buf[p..p + cdr.comment_len as usize].into()) | 131 | let comment = if bit_flag.is_utf8() { |
| 126 | .map_err(|_| ZipError::InvalidFileComment)?; | 132 | String::from_utf8(buf[p..p + cdr.comment_len as usize].to_vec()) |
| 133 | .map_err(|_| ZipError::InvalidFileComment)? | ||
| 134 | } else { | ||
| 135 | String::from_cp437(&buf[p..p + cdr.comment_len as usize]) | ||
| 136 | }; | ||
| 127 | p += cdr.comment_len as usize; | 137 | p += cdr.comment_len as usize; |
| 128 | 138 | ||
| 129 | let mut compressed_size = cdr.compressed_size as u64; | 139 | let mut compressed_size = cdr.compressed_size as u64; |
| @@ -209,7 +219,7 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> { | |||
| 209 | name.clone(), | 219 | name.clone(), |
| 210 | ZipFileInfo::new( | 220 | ZipFileInfo::new( |
| 211 | CompressionMethod::from_struct_id(cdr.compression_method)?, | 221 | CompressionMethod::from_struct_id(cdr.compression_method)?, |
| 212 | BitFlag::new(cdr.bit_flag), | 222 | bit_flag, |
| 213 | mtime, | 223 | mtime, |
| 214 | atime, | 224 | atime, |
| 215 | ctime, | 225 | ctime, |
diff --git a/src/zip/error.rs b/src/zip/error.rs index c77370b..3eb68b8 100644 --- a/src/zip/error.rs +++ b/src/zip/error.rs | |||
| @@ -11,7 +11,6 @@ pub enum ZipError { | |||
| 11 | InvalidFileHeaderSignature, | 11 | InvalidFileHeaderSignature, |
| 12 | InvalidCDRSignature, | 12 | InvalidCDRSignature, |
| 13 | 13 | ||
| 14 | InvalidArchiveComment, | ||
| 15 | InvalidCompressionMethod, | 14 | InvalidCompressionMethod, |
| 16 | UnsupportedCompressionMethod, | 15 | UnsupportedCompressionMethod, |
| 17 | InvalidDate, | 16 | InvalidDate, |
| @@ -49,7 +48,6 @@ impl Display for ZipError { | |||
| 49 | write!(f, "Invalid signature of central directory record") | 48 | write!(f, "Invalid signature of central directory record") |
| 50 | } | 49 | } |
| 51 | 50 | ||
| 52 | Self::InvalidArchiveComment => write!(f, "Invalid archive comment"), | ||
| 53 | Self::InvalidCompressionMethod => writeln!(f, "Invalid compression method"), | 51 | Self::InvalidCompressionMethod => writeln!(f, "Invalid compression method"), |
| 54 | Self::UnsupportedCompressionMethod => writeln!(f, "Unsupported compression method"), | 52 | Self::UnsupportedCompressionMethod => writeln!(f, "Unsupported compression method"), |
| 55 | Self::InvalidDate => write!(f, "Invalid date"), | 53 | Self::InvalidDate => write!(f, "Invalid date"), |
diff --git a/src/zip/mod.rs b/src/zip/mod.rs index 0f19824..bcc34ed 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | mod archive; | 1 | mod archive; |
| 2 | mod cp437; | ||
| 2 | mod driver; | 3 | mod driver; |
| 3 | mod error; | 4 | mod error; |
| 4 | mod file; | 5 | mod file; |
diff --git a/src/zip/tests.rs b/src/zip/tests.rs index 92a9c3f..e24cdfe 100644 --- a/src/zip/tests.rs +++ b/src/zip/tests.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | use crate::zip::cp437::{from_char, is_cp437, to_char, FromCp437}; | ||
| 1 | use crate::zip::{bit::DeflateMode, BitFlag}; | 2 | use crate::zip::{bit::DeflateMode, BitFlag}; |
| 2 | 3 | ||
| 3 | #[test] | 4 | #[test] |
| @@ -40,3 +41,36 @@ fn test_bit_flag() { | |||
| 40 | bit_flag.set_deflate_mode(DeflateMode::Normal); | 41 | bit_flag.set_deflate_mode(DeflateMode::Normal); |
| 41 | assert_eq!(bit_flag.deflate_mode(), DeflateMode::Normal); | 42 | assert_eq!(bit_flag.deflate_mode(), DeflateMode::Normal); |
| 42 | } | 43 | } |
| 44 | |||
| 45 | #[test] | ||
| 46 | fn test_cp437() { | ||
| 47 | for b in 0..=255 { | ||
| 48 | assert_eq!(from_char(to_char(b)).unwrap(), b); | ||
| 49 | assert!(is_cp437(to_char(b)), "byte: {}", b); | ||
| 50 | } | ||
| 51 | |||
| 52 | assert_eq!(from_char('Σ'), Some(228)); | ||
| 53 | assert_eq!(from_char('§'), None); | ||
| 54 | |||
| 55 | assert!(is_cp437('Σ')); | ||
| 56 | assert!(!is_cp437('§')); | ||
| 57 | |||
| 58 | assert_eq!( | ||
| 59 | Vec::from_cp437("hello world").unwrap(), | ||
| 60 | [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100] | ||
| 61 | ); | ||
| 62 | assert_eq!( | ||
| 63 | String::from_cp437([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]), | ||
| 64 | "hello world" | ||
| 65 | ); | ||
| 66 | |||
| 67 | assert_eq!( | ||
| 68 | Vec::from_cp437("ABCDEFGHIJKLMNOPQRSTUVWXYZ").unwrap(), | ||
| 69 | (65..=90).collect::<Vec<u8>>() | ||
| 70 | ); | ||
| 71 | |||
| 72 | assert_eq!( | ||
| 73 | String::from_cp437((97..=122).collect::<Vec<u8>>()), | ||
| 74 | "abcdefghijklmnopqrstuvwxyz" | ||
| 75 | ); | ||
| 76 | } | ||
