Как кодировать расширенный римский ASCII / macOS (символы от 128 до 255) на 1 байт в Swift? - PullRequest
0 голосов
/ 28 марта 2019

Я пытаюсь написать файл .txt с расширенным кодом ASCII, но мне нужно сделать это на 8-битных символах.

Я бы хотел получить расширенный ASCII от Codepage 437, но я могу жить с Mac OS Roman.Но так как он работает с числами, он не должен иметь никакого значения.

При использовании Character(UnicodeScalar(unicodePosition)) он хорошо работает от 0 до 127. Каждый символ 8-битный.Начиная со 128-го скаляра, они не являются ASCII / macOS Roman и кодируются в 16 битах.

Таким образом, я могу создать массив UInt8 с конкретными символами, которые я хочу сохранить в файл.

let firstCharacter: UInt8 = 240 // Apple Logo in macOS Roman or "≡" in codepage 437

let secondCharacter: UInt8 = 236 // Infinity symbol on codepage 437 or "I" with two dots in macOS Roman

let listOfCharacters: [UInt8] = [firstCharacter, secondCharacter]

Но я понятия не имею, как сохранить такой список в файл, а затем отобразить его как расширенную римскую кодировку ASCII или macOS.

Мне нужно работать с этими числами, потому что я 'Я пытаюсь реализовать Vigenre Cipher для расширенного алфавита ASCII (или macOS Roman), и мне нужно, чтобы 8-битный ввод был 8-битным, чтобы содержимое файла имело точно такой же размер файла.Я должен сделать это на 256 символах, поэтому мне нужен расширенный ascii / macOS Roman.

Мне также нужно было бы прочитать этот тип файла обратно, поэтому метод чтения текстильно закодированс расширенной ASCII также будет приветствоваться.Наверное, поэтому есть String.Encoding.nonLossyASCII, а не только .ascii?

Ответы [ 3 ]

3 голосов
/ 28 марта 2019

Кодовая страница 437 доступна как CFStringEncodings.dosLatinUS и может быть преобразована в String.Encoding как в Как использовать кодирование Big5 в Swift на iOS :

let cfEnc = CFStringEncodings.dosLatinUS
let nsEnc = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(cfEnc.rawValue))
let encoding = String.Encoding(rawValue: nsEnc) // String.Encoding

Теперь вы можете преобразовать байты в строку и обратно:

let bytes = Data([240, 236])
// CP437 to string:
if let string = String(data: bytes, encoding: encoding) {
    print(string) // ≡∞
    // String to CP437:
    if let bytes2 = string.data(using: encoding) {
        print(Array(bytes2)) // [240, 236]
    }
}
2 голосов
/ 28 марта 2019

Простой подход состоит в том, чтобы начать с экземпляра String, преобразовать его в Data, используя указанную кодировку, а затем преобразовать его в массив [UInt8]:

let text = "The quick brown fox ... éâ..."
let data = text.data(using: .macOSRoman)
let characters [UInt8](data)

Будьте осторожны с вашим шифрованием,Большинство символов в диапазоне от 0 до 31 не могут быть представлены в тексте.Они могут не встречаться в оригинальном тексте.Но они появятся в зашифрованном тексте.Если вы не избежите этого, результатом будут двоичные данные, которые больше не могут быть преобразованы в читаемый текст.

0 голосов
/ 28 марта 2019

Итак, мое окончательное решение выглядит так:

class FileManager {

    let encoding: String.Encoding

    init() {
        let cfEnc = CFStringEncodings.dosLatinUS
        let nsEnc = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(cfEnc.rawValue))
        let encoding = String.Encoding(rawValue: nsEnc)
        self.encoding = encoding
    }

    func loadFromFile(path: String) -> Data {
        return NSData(contentsOfFile: path)! as Data
    }

    func saveToFile(data: Data, path: String) {
        let string = dataToPage437String(data: data)
        let fileURL = URL(fileURLWithPath: path)
        try? string?.write(to: fileURL, atomically: false, encoding: encoding)
    }

    func page437StringToData(string: String) -> Data? {
         return string.data(using: encoding)
    }

    private func dataToPage437String(data: Data) -> String? {
        return String(data: data, encoding: encoding)
    }
}
class EncryptionEngine {

    func encrypt(originalData: Data, keyData: Data) -> Data {
        var encryptedData = [UInt8]()

        for (index, byte) in originalData.enumerated() {
            let indexInCurrentBlock = index % keyData.count
            let row = Int(byte)
            let column = Int(keyData[indexInCurrentBlock])
            //for pure Vigenère cipher modifier should be 0
            let modifier = index + 1
            let encryptedCharacter = UInt8((row + column + modifier) % 256)
            encryptedData.append(encryptedCharacter)
        }

        return Data(encryptedData)
    }
}
        let fileManager = FileManager()
        let encryptionEngine = EncryptionEngine()
        let originalData = fileManager.loadFromFile(path: "/Path/test2.txt")
        guard let keyData = fileManager.page437StringToData(string: "keyToEncryptTakenFromTextField") else { return }
        let encryptedData = encryptionEngine.encrypt(originalData: originalData, keyData: keyData)
        fileManager.saveToFile(data: encryptedData, path: "/Path/test_enc.txt")
...