I'm trying to write a .txt
file with extended ASCII code, but I need to do it on 8-bit characters.
I'd love to get extended ASCII from Codepage 437
, but I can live with Mac OS Roman
. But as it's operation on numbers, it shouldn't make any difference.
When using Character(UnicodeScalar(unicodePosition))
, it works well for 0 to 127. Each character is 8-bit. From 128th scalar up, they are not ASCII/macOS Roman and they're encoded on 16 bits.
So I can create an array of UInt8
with specific characters that I want to save to file.
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]
But I have no idea on how to save such a list to a file, and then display it as extendedASCII or macOS Roman encoding.
I need to operate on this numbers because I'm trying to implement Vigenre Cipher for extended ASCII alphabet (or macOS Roman) and I need the 8-bit input to be 8-bit output so the content of the file have exactly the same file size. I have to do it on 256 characters, hence I need extended ascii/macOS Roman.
I'd also need to read this kind of file back, so method for reading a textile encoded with extended ASCII would also be appreciated. I guess that's why there's String.Encoding.nonLossyASCII
and not only .ascii
?
Codepage 437 is available as CFStringEncodings.dosLatinUS
and can be converted to a String.Encoding
as in How to use Big5 encoding in Swift on iOS :
let cfEnc = CFStringEncodings.dosLatinUS
let nsEnc = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(cfEnc.rawValue))
let encoding = String.Encoding(rawValue: nsEnc) // String.Encoding
Now you can convert the bytes to a string and back:
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]
}
}
The simple approach is to start with a String
instance, convert it to Data
using a specified encoding and then convert it the [UInt8]
array:
let text = "The quick brown fox ... éâ..."
let data = text.data(using: .macOSRoman)
let characters [UInt8](data)
Be carefule with your encryption. Most characters in the range between 0 and 31 cannot be represented in text. They might not occur in the original text. But they will appear in the encrypted text. If you don't avoid it, the result will be binary data that can no longer be converted to readable text.
So my final solution looks like this:
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")
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.