-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Support chunk upload in Swift
(box/box-codegen#513)
(#142)
- Loading branch information
1 parent
8673a24
commit 9e0b4e2
Showing
12 changed files
with
475 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
{ "engineHash": "1dc8a5d", "specHash": "ee83bc7", "version": "0.1.0" } | ||
{ "engineHash": "06b32a5", "specHash": "ee83bc7", "version": "0.1.0" } |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import Foundation | ||
|
||
/// Extension providing convenience methods for handling data. | ||
public extension Data { | ||
|
||
/// Initializes `Data` from a value of generic type `T`. | ||
/// | ||
/// - Parameter value: The value to convert into `Data`. | ||
internal init<T>(value: T) { | ||
self = withUnsafePointer(to: value) { (ptr: UnsafePointer<T>) -> Data in | ||
return Data(buffer: UnsafeBufferPointer(start: ptr, count: 1)) | ||
} | ||
} | ||
|
||
/// Appends a value of generic type `T` to the end of `Data`. | ||
/// | ||
/// - Parameter value: The value to append to `Data`. | ||
internal mutating func append<T>(value: T) { | ||
withUnsafePointer(to: value) { (ptr: UnsafePointer<T>) in | ||
append(UnsafeBufferPointer(start: ptr, count: 1)) | ||
} | ||
} | ||
|
||
/// Initializes `Data` from a hexadecimal string. | ||
/// | ||
/// - Parameter hex: The hexadecimal string representation of the data. | ||
/// - Returns: An optional `Data` object initialized from the hexadecimal string, or `nil` if the string is invalid. | ||
init?(fromHexString hex: String) { | ||
guard hex.count % 2 == 0 else { | ||
return nil | ||
} | ||
|
||
var data = Data() | ||
var index = hex.startIndex | ||
while index < hex.endIndex { | ||
let nextIndex = hex.index(index, offsetBy: 2) | ||
let byteString = hex[index..<nextIndex] | ||
guard let byte = UInt8(byteString, radix: 16) else { | ||
return nil | ||
} | ||
data.append(byte) | ||
index = nextIndex | ||
} | ||
|
||
self = data | ||
} | ||
|
||
/// Returns the `Data` object as a base64-encoded string. | ||
/// | ||
/// - Returns: A base64-encoded string representation of the `Data`. | ||
func base64EncodedString() -> String { | ||
return self.base64EncodedString(options: []) | ||
} | ||
|
||
/// Returns the `Data` object as a hexadecimal string. | ||
/// | ||
/// - Returns: A hexadecimal string representation of the `Data`. | ||
func hexString() -> String { | ||
let hexBytes = self.map { String(format: "%02hhx", $0) } | ||
return hexBytes.joined() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import Foundation | ||
|
||
/// Enum defining available hashing algorithms. | ||
public enum HashName { | ||
/// SHA-1 hashing algorithm. | ||
case sha1 | ||
} | ||
|
||
/// Class for hashing data using a specified algorithm. | ||
public class Hash { | ||
private static let Base64Encoding = "base64" | ||
|
||
private let algorithm: HashName | ||
private var data: Data | ||
|
||
/// Initializes a `Hash` instance with the specified algorithm. | ||
/// | ||
/// - Parameter algorithm: The hashing algorithm to use. | ||
public init(algorithm: HashName) { | ||
self.algorithm = algorithm | ||
self.data = Data() | ||
} | ||
|
||
/// Updates the hash with additional data. | ||
/// | ||
/// - Parameter data: The data to append to the hash. | ||
public func updateHash(data: Data) { | ||
self.data.append(data) | ||
} | ||
|
||
/// Calculates the digest of the accumulated data using the specified encoding. | ||
/// | ||
/// - Parameter encoding: The string encoding to use for the digest result. | ||
/// - Returns: The base64-encoded or hexadecimal string representation of the hash digest. | ||
public func digestHash(encoding: String) async -> String { | ||
var digest = Data() | ||
|
||
switch algorithm { | ||
case .sha1: | ||
digest = SHA1.sha1(data: data) | ||
} | ||
|
||
if encoding == Self.Base64Encoding { | ||
return digest.base64EncodedString() | ||
} else { | ||
return digest.hexString() | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import Foundation | ||
|
||
struct SHA1 { | ||
// Hash initial values | ||
private static let h0: UInt32 = 0x67452301 | ||
private static let h1: UInt32 = 0xEFCDAB89 | ||
private static let h2: UInt32 = 0x98BADCFE | ||
private static let h3: UInt32 = 0x10325476 | ||
private static let h4: UInt32 = 0xC3D2E1F0 | ||
|
||
static func sha1(data: Data) -> Data { | ||
var message = data | ||
let messageLength = UInt64(message.count * 8) | ||
|
||
// Padding the message | ||
message.append(0x80) | ||
while (message.count % 64) != 56 { | ||
message.append(0x00) | ||
} | ||
|
||
// Append the length of the original message as a 64-bit big-endian integer | ||
let lengthBytes = messageLength.bigEndian | ||
message.append(value: lengthBytes) | ||
|
||
// Initialize hash values | ||
var h:[UInt32]=[SHA1.h0,SHA1.h1,SHA1.h2,SHA1.h3,SHA1.h4] | ||
|
||
// Process the message in successive 512-bit chunks | ||
for chunkOffset in stride(from: 0, to: message.count, by: 64) { | ||
let chunk = message[chunkOffset..<chunkOffset + 64] | ||
var words = [UInt32](repeating: 0, count: 80) | ||
|
||
// Break chunk into sixteen 32-bit big-endian words | ||
for i in 0..<16 { | ||
let start = chunk.index(chunk.startIndex, offsetBy: i * 4) | ||
let end = chunk.index(start, offsetBy: 4) | ||
words[i] = UInt32(bigEndian: chunk[start..<end].withUnsafeBytes { $0.load(as: UInt32.self) }) | ||
} | ||
|
||
// Extend the sixteen 32-bit words into eighty 32-bit words | ||
for i in 16..<80 { | ||
words[i] = leftRotate(words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16], by: 1) | ||
} | ||
|
||
// Initialize hash value for this chunk | ||
var a = h[0] | ||
var b = h[1] | ||
var c = h[2] | ||
var d = h[3] | ||
var e = h[4] | ||
|
||
// Main loop | ||
for i in 0..<80 { | ||
var f: UInt32 = 0 | ||
var k: UInt32 = 0 | ||
|
||
switch i { | ||
case 0...19: | ||
f = (b & c) | ((bitwiseNot(b)) & d) | ||
k = 0x5A827999 | ||
case 20...39: | ||
f = b ^ c ^ d | ||
k = 0x6ED9EBA1 | ||
case 40...59: | ||
f = (b & c) | (b & d) | (c & d) | ||
k = 0x8F1BBCDC | ||
case 60...79: | ||
f = b ^ c ^ d | ||
k = 0xCA62C1D6 | ||
default: | ||
break | ||
} | ||
|
||
let temp = leftRotate(a, by: 5) &+ f &+ e &+ k &+ words[i] | ||
e = d | ||
d = c | ||
c = leftRotate(b, by: 30) | ||
b = a | ||
a = temp | ||
} | ||
|
||
// Add this chunk's hash to result so far | ||
h[0] = h[0] &+ a | ||
h[1] = h[1] &+ b | ||
h[2] = h[2] &+ c | ||
h[3] = h[3] &+ d | ||
h[4] = h[4] &+ e | ||
} | ||
|
||
// Produce the final hash value (big-endian) | ||
var hash = Data() | ||
[h[0], h[1], h[2], h[3], h[4]].forEach { | ||
let bigEndianValue = $0.bigEndian | ||
hash.append(value: bigEndianValue) | ||
} | ||
|
||
return hash | ||
} | ||
|
||
private static func bitwiseNot<T: FixedWidthInteger>(_ value: T) -> T { | ||
return value ^ T.max | ||
} | ||
|
||
private static func leftRotate(_ value: UInt32, by bits: UInt32) -> UInt32 { | ||
return (value << bits) | (value >> (32 - bits)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.