123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- //
- // Base64.swift
- // SwiftyBeaver (macOS)
- //
- // Copyright © 2017 Sebastian Kreutzberger. All rights reserved.
- //
- #if os(Linux)
- import Foundation
- struct InvalidBase64: Error {}
- struct Base64 {
- static func decode(_ string: String) throws -> [UInt8] {
- return try decode([UInt8](string.utf8))
- }
- /// Decodes a Base64 encoded String into Data
- ///
- /// - throws: If the string isn't base64 encoded
- static func decode(_ string: [UInt8]) throws -> [UInt8] {
- let lookupTable: [UInt8] = [
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 62, 64, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
- 64, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 63,
- 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
- ]
- let remainder = string.count % 4
- let length = (string.count - remainder) / 4
- var decoded = [UInt8]()
- decoded.reserveCapacity(length)
- var index = 0
- var i0: UInt8 = 0
- var i1: UInt8 = 0
- var i2: UInt8 = 0
- var i3: UInt8 = 0
- while index &+ 4 < string.count {
- i0 = lookupTable[numericCast(string[index])]
- i1 = lookupTable[numericCast(string[index &+ 1])]
- i2 = lookupTable[numericCast(string[index &+ 2])]
- i3 = lookupTable[numericCast(string[index &+ 3])]
- if i0 > 63 || i1 > 63 || i2 > 63 || i3 > 63 {
- throw InvalidBase64()
- }
- decoded.append(i0 << 2 | i1 >> 4)
- decoded.append(i1 << 4 | i2 >> 2)
- decoded.append(i2 << 6 | i3)
- index += 4
- }
- if string.count &- index > 1 {
- i0 = lookupTable[numericCast(string[index])]
- i1 = lookupTable[numericCast(string[index &+ 1])]
- if i1 > 63 {
- guard string[index] == 61 else {
- throw InvalidBase64()
- }
- return decoded
- }
- if i2 > 63 {
- guard string[index &+ 2] == 61 else {
- throw InvalidBase64()
- }
- return decoded
- }
- decoded.append(i0 << 2 | i1 >> 4)
- if string.count &- index > 2 {
- i2 = lookupTable[numericCast(string[index &+ 2])]
- if i2 > 63 {
- guard string[index &+ 2] == 61 else {
- throw InvalidBase64()
- }
- return decoded
- }
- decoded.append(i1 << 4 | i2 >> 2)
- if string.count &- index > 3 {
- i3 = lookupTable[numericCast(string[index &+ 3])]
- if i3 > 63 {
- guard string[index &+ 3] == 61 else {
- throw InvalidBase64()
- }
- return decoded
- }
- decoded.append(i2 << 6 | i3)
- }
- }
- }
- return decoded
- }
- static func encode(_ data: [UInt8]) -> String {
- let base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
- var encoded: String = ""
- func appendCharacterFromBase(_ character: Int) {
- encoded.append(base64[base64.index(base64.startIndex, offsetBy: character)])
- }
- func byte(_ index: Int) -> Int {
- return Int(data[index])
- }
- let decodedBytes = data.map { Int($0) }
- var i = 0
- while i < decodedBytes.count - 2 {
- appendCharacterFromBase((byte(i) >> 2) & 0x3F)
- appendCharacterFromBase(((byte(i) & 0x3) << 4) | ((byte(i + 1) & 0xF0) >> 4))
- appendCharacterFromBase(((byte(i + 1) & 0xF) << 2) | ((byte(i + 2) & 0xC0) >> 6))
- appendCharacterFromBase(byte(i + 2) & 0x3F)
- i += 3
- }
- if i < decodedBytes.count {
- appendCharacterFromBase((byte(i) >> 2) & 0x3F)
- if i == decodedBytes.count - 1 {
- appendCharacterFromBase(((byte(i) & 0x3) << 4))
- encoded.append("=")
- } else {
- appendCharacterFromBase(((byte(i) & 0x3) << 4) | ((byte(i + 1) & 0xF0) >> 4))
- appendCharacterFromBase(((byte(i + 1) & 0xF) << 2))
- }
- encoded.append("=")
- }
- return encoded
- }
- }
- #endif
|