Port other static methods in QRSegment to Swift

pull/82/head
fwcd 6 years ago
parent c72f536b08
commit 78c2631c42

@ -21,6 +21,14 @@
* Software. * Software.
*/ */
/// The set of all legal characters in alphanumeric mode,
/// where each character value maps to the index in the string.
fileprivate let alphanumericCharset: [Character] = [
"0","1","2","3","4","5","6","7","8","9",
"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z",
" ","$","%","*","+","-",".","/",":"
]
/*---- QrSegment functionality ----*/ /*---- QrSegment functionality ----*/
/// A segment of character/binary/control data in a QR Code symbol. /// A segment of character/binary/control data in a QR Code symbol.
@ -38,9 +46,9 @@
public struct QRSegment: Hashable { public struct QRSegment: Hashable {
/// The mode indicator of this segment. /// The mode indicator of this segment.
public let mode: Mode public let mode: Mode
/// The length of this segment's unencoded data. Measured in characters for /// The length of this segment"s unencoded data. Measured in characters for
/// numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode. /// numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode.
/// Not the same as the data's bit length. /// Not the same as the data"s bit length.
public let numChars: UInt public let numChars: UInt
/// The data bits of this segment. /// The data bits of this segment.
public let data: [Bool] public let data: [Bool]
@ -52,7 +60,7 @@ public struct QRSegment: Hashable {
/// All input byte slices are acceptable. /// All input byte slices are acceptable.
/// ///
/// Any text string can be converted to UTF-8 bytes and encoded as a byte mode segment. /// Any text string can be converted to UTF-8 bytes and encoded as a byte mode segment.
public static func makeBytes(data: [UInt8]) -> Self { public static func makeBytes(_ data: [UInt8]) -> Self {
var bb = BitBuffer([]) var bb = BitBuffer([])
for b in data { for b in data {
bb.appendBits(UInt32(b), 8) bb.appendBits(UInt32(b), 8)
@ -63,7 +71,7 @@ public struct QRSegment: Hashable {
/// Returns a segment representing the given string of decimal digits encoded in numeric mode. /// Returns a segment representing the given string of decimal digits encoded in numeric mode.
/// ///
/// Panics if the string contains non-digit characters. /// Panics if the string contains non-digit characters.
public static func makeNumeric(text: [Character]) -> Self { public static func makeNumeric(_ text: [Character]) -> Self {
var bb = BitBuffer([]) var bb = BitBuffer([])
var accumData: UInt32 = 0 var accumData: UInt32 = 0
var accumCount: UInt8 = 0 var accumCount: UInt8 = 0
@ -89,7 +97,7 @@ public struct QRSegment: Hashable {
/// dollar, percent, asterisk, plus, hyphen, period, slash, colon. /// dollar, percent, asterisk, plus, hyphen, period, slash, colon.
/// ///
/// Panics if the string contains non-encodable characters. /// Panics if the string contains non-encodable characters.
public static func makeAlphanumeric(text: [Character]) -> Self { public static func makeAlphanumeric(_ text: [Character]) -> Self {
var bb = BitBuffer([]) var bb = BitBuffer([])
var accumData: UInt32 = 0 var accumData: UInt32 = 0
var accumCount: UInt32 = 0 var accumCount: UInt32 = 0
@ -115,7 +123,7 @@ public struct QRSegment: Hashable {
/// ///
/// The result may use various segment modes and switch /// The result may use various segment modes and switch
/// modes to optimize the length of the bit stream. /// modes to optimize the length of the bit stream.
public static func makeSegments(text: [Character]) -> Self { public static func makeSegments(_ text: [Character]) -> Self {
if text.isEmpty { if text.isEmpty {
return [] return []
} else if QRSegment.isNumeric(text) { } else if QRSegment.isNumeric(text) {
@ -145,4 +153,46 @@ public struct QRSegment: Hashable {
} }
return QRSegment(mode: .eci, numChars: 0, data: bb.bits) return QRSegment(mode: .eci, numChars: 0, data: bb.bits)
} }
/*---- Constructor (low level) ----*/
/// Creates a new QR Code segment with the given attributes and data.
///
/// The character count (numchars) must agree with the mode and
/// the bit buffer length, but the constraint isn"t checked.
public init(mode: Mode, numChars: UInt, data: [Bool]) {
self.mode = mode
self.numChars = numChars
self.data = data
}
/*---- Other static functions ----*/
/// Calculates and returns the number of bits needed to encode the given
/// segments at the given version. The result is None if a segment has too many
/// characters to fit its length field, or the total bits exceeds usize::MAX.
public static func getTotalBits(segments: [Self], version: Version) -> UInt? {
var result: UInt = 0
for seg in segments {
let ccBits = seg.mode.numCharCountBits(version: version)
guard seg.numChars < (1 << ccBits) else {
return nil // The segment"s length doesn't fit the field's bit width
}
result += 4 + UInt(ccBits) + seg.data.count
}
return result
}
/// Tests whether the given string can be encoded as a segment in alphanumeric mode.
/// A string is encodable iff each character is in the following set: 0 to 9, A to Z
/// (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
public static func isAlphanumeric(_ text: [Character]) -> Bool {
text.allSatisfy { alphanumericCharset.contains($0) }
}
// Tests whether the given string can be encoded as a segment in numeric mode.
// A string is encodable iff each character is in the range 0 to 9.
public static func isNumeric(_ text: [Character]) -> Bool {
text.allSatisfy { $0.isNumber }
}
} }

Loading…
Cancel
Save