-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathRLP.swift
More file actions
executable file
·98 lines (85 loc) · 3.25 KB
/
RLP.swift
File metadata and controls
executable file
·98 lines (85 loc) · 3.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// Created by Aleph Retamal on 31/1/18.
// Copyright © 2018 Lalacode. All rights reserved.
public enum RLP {
public enum Error: Swift.Error {
case stringToData
case dataToString
case invalidObject(ofType: Any.Type, expected: Any.Type)
public var localizedDescription: String {
switch self {
case .stringToData: return "Failed to convert String to Data"
case .dataToString: return "Failed to convert Data to String"
case .invalidObject(let got, let expected):
return "Invalid object, expected \(expected), but got \(got)"
}
}
}
}
// MARK: Internal helpers
internal extension RLP {
static func binaryLength(of n: UInt32) -> UInt8 {
return UInt8(ceil(log10(Double(n))/log10(Double(UInt8.max))))
}
static func encodeLength(_ length: UInt32, offset: UInt8) -> Data {
if length < 56 {
let lengthByte = offset + UInt8(length)
return Data(bytes: [lengthByte])
} else {
let firstByte = offset + 55 + binaryLength(of: length)
var bytes = [firstByte]
bytes.append(contentsOf: length.byteArrayLittleEndian)
return Data(bytes: bytes)
}
}
}
// MARK: Data encoding
public extension RLP {
public static func encode(_ data: Data) -> Data {
if data.count == 1,
0x00...0x7f ~= data[0] {
return data
} else {
var result = encodeLength(UInt32(data.count), offset: 0x80)
result.append(contentsOf: data)
return result
}
}
public static func encode(nestedArrayOfData array: [Any]) throws -> Data {
var output = Data()
for item in array {
if let data = item as? Data {
output.append(encode(data))
} else if let array = item as? [Any] {
output.append(try encode(nestedArrayOfData: array))
} else {
throw Error.invalidObject(ofType: Mirror(reflecting: item).subjectType, expected: Data.self)
}
}
let encodedLength = encodeLength(UInt32(output.count), offset: 0xc0)
output.insert(contentsOf: encodedLength, at: 0)
return output
}
}
// MARK: String encoding
public extension RLP {
public static func encode(_ string: String, with encoding: String.Encoding = .ascii) throws -> Data {
guard let data = string.data(using: encoding) else {
throw Error.stringToData
}
let bytes = encode(data)
return bytes
}
public static func encode(nestedArrayOfString array: [Any], encodeStringsWith encoding: String.Encoding = .ascii) throws -> Data {
var output = Data()
for item in array {
if let string = item as? String {
output.append(try encode(string, with: .ascii))
} else if let array = item as? [Any] {
output.append(try encode(nestedArrayOfString: array, encodeStringsWith: encoding))
} else {
throw Error.invalidObject(ofType: Mirror(reflecting: item).subjectType, expected: String.self)
}
}
return output
}
}