cleanup
[pspp] / rust / src / encoding.rs
1 use crate::locale_charset::locale_charset;
2 use encoding_rs::{Encoding, UTF_8};
3
4 include!(concat!(env!("OUT_DIR"), "/encodings.rs"));
5
6 pub fn codepage_from_encoding(encoding: &str) -> Option<u32> {
7     CODEPAGE_NAME_TO_NUMBER
8         .get(encoding.to_ascii_lowercase().as_str())
9         .copied()
10 }
11
12 use thiserror::Error as ThisError;
13
14 #[derive(ThisError, Debug)]
15 pub enum Error {
16     #[error("This system file does not indicate its own character encoding.  For best results, specify an encoding explicitly.  Use SYSFILE INFO with ENCODING=\"DETECT\" to analyze the possible encodings.")]
17     NoEncoding,
18
19     #[error("This system file encodes text strings with unknown code page {0}.")]
20     UnknownCodepage(i32),
21
22     #[error("This system file encodes text strings with unknown encoding {0}.")]
23     UnknownEncoding(String),
24
25     #[error("This system file is encoded in EBCDIC, which is not supported.")]
26     Ebcdic,
27 }
28
29 pub fn default_encoding() -> &'static Encoding {
30     lazy_static! {
31         static ref DEFAULT_ENCODING: &'static Encoding =
32             Encoding::for_label(locale_charset().as_bytes()).unwrap_or(UTF_8);
33     }
34     &DEFAULT_ENCODING
35 }
36
37 pub fn get_encoding(
38     encoding: Option<&str>,
39     character_code: Option<i32>,
40 ) -> Result<&'static Encoding, Error> {
41     let label = if let Some(encoding) = encoding {
42         encoding
43     } else if let Some(codepage) = character_code {
44         match codepage {
45             1 => return Err(Error::Ebcdic),
46             2 | 3 => {
47                 // These ostensibly mean "7-bit ASCII" and "8-bit ASCII"[sic]
48                 // respectively.  However, many files have character code 2 but
49                 // data which are clearly not ASCII.  Therefore, ignore these
50                 // values.
51                 return Err(Error::NoEncoding);
52             }
53             4 => "MS_KANJI",
54             _ => CODEPAGE_NUMBER_TO_NAME
55                 .get(&codepage)
56                 .copied()
57                 .ok_or(Error::UnknownCodepage(codepage))?,
58         }
59     } else {
60         return Err(Error::NoEncoding);
61     };
62
63     Encoding::for_label(label.as_bytes()).ok_or(Error::UnknownEncoding(label.into()))
64 }