5tsu75y8.rs
| 5.8 kB | torrent | get
.
/* NOTE: Most of this file is copypasta from huawei-modem, the only new code is in `fn main()` */

/// Lookup table for 'extended' GSM characters (characters which are encoded as `'\x1B'` plus
/// whatever this table says).
pub static GSM_EXTENDED_ENCODING_TABLE: [(char, u8); 9] = [
    ('^', 0x14),
    ('{', 0x28),
    ('}', 0x29),
    ('\\', 0x2F),
    ('[', 0x3C),
    ('~', 0x3D),
    (']', 0x3E),
    ('|', 0x40),
    ('\u{20AC}', 0x65)
];
/// Lookup table for non-alphanumeric characters in the GSM alphabet.
pub static GSM_ENCODING_TABLE: [(char, u8); 65] = [
    ('@', 0x00),
    ('\u{00A3}', 0x01),
    ('$', 0x02),
    ('\u{00A5}', 0x03),
    ('è', 0x04),
    ('é', 0x05),
    ('ù', 0x06),
    ('ì', 0x07),
    ('ò', 0x08),
    ('\u{00C7}', 0x09),
    ('\n', 0x0a),
    ('\u{00D8}', 0x0b),
    ('\u{00F8}', 0x0c),
    ('\r', 0x0d),
    ('\u{00C5}', 0x0e),
    ('\u{00E5}', 0x0f),
    ('\u{0394}', 0x10),
    ('_', 0x11),
    ('\u{03A6}', 0x12),
    ('Γ', 0x13),
    ('Λ', 0x14),
    ('Ω', 0x15),
    ('Π', 0x16),
    ('Ψ', 0x17),
    ('Σ', 0x18),
    ('Θ', 0x19),
    ('Ξ', 0x1A),
    ('Æ', 0x1C),
    ('æ', 0x1D),
    ('ß', 0x1E),
    ('É', 0x1F),
    (' ', 0x20),
    ('!', 0x21),
    ('"', 0x22),
    ('#', 0x23),
    ('¤', 0x24),
    ('%', 0x25),
    ('&', 0x26),
    ('\'', 0x27),
    ('(', 0x28),
    (')', 0x29),
    ('*', 0x2A),
    ('+', 0x2B),
    (',', 0x2C),
    ('-', 0x2D),
    ('.', 0x2E),
    ('/', 0x2F),
    (':', 0x3A),
    (';', 0x3B),
    ('<', 0x3C),
    ('=', 0x3D),
    ('>', 0x3E),
    ('?', 0x3F),
    ('¡', 0x40),
    ('Ä', 0x5B),
    ('Ö', 0x5C),
    ('Ñ', 0x5D),
    ('Ü', 0x5E),
    ('§', 0x5F),
    ('¿', 0x60),
    ('ä', 0x7B),
    ('ö', 0x7C),
    ('ñ', 0x7D),
    ('ü', 0x7E),
    ('à', 0x7F)
];


/// Decode a GSM 7-bit-encoded buffer into a string.
///
/// **Warning:** You need to unpack the string first; this method operates on unpacked septets, not
/// packed septets. See the `pdu` module for more.
///
/// This method is lossy, and doesn't complain about crap that it can't decode.
pub fn gsm_decode_string(input: &[u8]) -> String {
    let mut ret = String::new();
    let mut skip = false;
    for (i, b) in input.iter().enumerate() {
        if skip {
            skip = false;
            continue;
        }
        match *b {
            b'A' ... b'Z' | b'a' ... b'z' | b'0' ... b'9' => {
                ret.push(*b as char);
            },
            0x1B => {
                if let Some(b) = input.get(i+1) {
                    for &(ch, val) in GSM_EXTENDED_ENCODING_TABLE.iter() {
                        if val == *b {
                            ret.push(ch);
                            skip = true;
                        }
                    }
                }
            },
            b => {
                for &(ch, val) in GSM_ENCODING_TABLE.iter() {
                    if val == b {
                        ret.push(ch);
                    }
                }
            }
        }
    }
    ret
}

/// Tries to encode a character into the given destination buffer, returning `true` if the
/// character was successfully encoded, and `false` if the character cannot be represented in the
/// GSM 7-bit encoding.
pub fn try_gsm_encode_char(b: char, dest: &mut Vec<u8>) -> bool {
    match b {
        'A' ... 'Z' | 'a' ... 'z' | '0' ... '9' => {
            dest.push(b as u8);
            return true;
        },
        b => {
            for &(ch, val) in GSM_ENCODING_TABLE.iter() {
                if b == ch {
                    dest.push(val);
                    return true;
                }
            }
            for &(ch, val) in GSM_EXTENDED_ENCODING_TABLE.iter() {
                if b == ch {
                    dest.push(0x1B);
                    dest.push(val);
                    return true;
                }
            }
        }
    }
    false
}
/// Tries to encode a string as GSM 7-bit, returning a buffer of **unpacked** septets iff all of
/// the data in `input` was representable in the 7-bit encoding.
///
/// **Warning:** The output of this function is unsuitable for transmission across the network;
/// you need to pack the septets first! See the `pdu` module for more.
pub fn try_gsm_encode_string(input: &str) -> Option<Vec<u8>> {
    let mut ret = vec![];
    for c in input.chars() {
        if !try_gsm_encode_char(c, &mut ret) {
            return None;
        }
    }
    Some(ret)
}

fn main() {
    let weird_text = "Π7Oß.ù\"GÅ&ì:Offù:åΠwùJà.ìJ6ù\"G.Π/>Ξì";
    let mut garboleum = try_gsm_encode_string(&weird_text).expect("couldn't encode weird text back");
    let mut garblestring = garboleum.iter().map(|x| format!("{x:07b}")).collect::<String>();
    let mut offset = 0;
    while !garblestring.is_empty() {
        let mut interpretation = String::new();
//        eprint!("{garblestring} => ");
        for text in garblestring.as_bytes().chunks(7) {
            let text = str::from_utf8(text).unwrap();
//            eprint!("{text} ");
            if text.len() < 7 && !text.is_empty() {
                continue;
            }
            match u8::from_str_radix(text, 2) {
                Ok(v) => {
//                    eprint!("({:?}) ", gsm_decode_string(&[v]));
                    interpretation.push_str(&gsm_decode_string(&[v]));
                },
                _ => /*eprint!("(???)")*/{},
            }
        }
//        eprintln!();
        eprintln!("offset {offset}: {interpretation:?}");
        offset += 1;
        garblestring.remove(0);
    }
}