diff --git a/swift/Sources/QRCodeGenerator/BitBuffer.swift b/swift/Sources/QRCodeGenerator/BitBuffer.swift
index b710178..ea648e2 100644
--- a/swift/Sources/QRCodeGenerator/BitBuffer.swift
+++ b/swift/Sources/QRCodeGenerator/BitBuffer.swift
@@ -33,7 +33,7 @@ public struct BitBuffer {
/// Appends the given number of low-order bits of the given value to this buffer.
///
/// Requires len ≤ 31 and val < 2len.
- public mutating func writeBits(_ value: UInt32, _ length: Int) {
+ public mutating func appendBits(_ value: UInt32, _ length: Int) {
assert(length <= 31 && (value >> length) == 0, "Value out of range")
bits.append((0.. Self {
+ var bb = BitBuffer([])
+ for b in data {
+ bb.appendBits(UInt32(b), 8)
+ }
+ return QRSegment(mode: .byte, numChars: data.count, data: bb.bits)
+ }
+
+ /// Returns a segment representing the given string of decimal digits encoded in numeric mode.
+ ///
+ /// Panics if the string contains non-digit characters.
+ public static func makeNumeric(text: [Character]) -> Self {
+ var bb = BitBuffer([])
+ var accumData: UInt32 = 0
+ var accumCount: UInt8 = 0
+ for c in text {
+ assert(c.isNumber && c.isASCII, "String contains non-numeric characters")
+ accumData = accumData * 10 + (UInt32(c.asciiValue!) - UInt32("0".asciiValue!))
+ accumCount += 1
+ if accumCount == 3 {
+ bb.appendBits(accumData, 10)
+ accumData = 0
+ accumCount = 0
+ }
+ }
+ if accumCount > 0 { // 1 or 2 digits remaining
+ bb.appendBits(accumData, accumCount * 3 + 1)
+ }
+ return QRSegment(mode: .numeric, numChars: text.count, data: bb.bits)
+ }
+
+ /// Returns a segment representing the given text string encoded in alphanumeric mode.
+ ///
+ /// The characters allowed are: 0 to 9, A to Z (uppercase only), space,
+ /// dollar, percent, asterisk, plus, hyphen, period, slash, colon.
+ ///
+ /// Panics if the string contains non-encodable characters.
+ public static func makeAlphanumeric(text: [Character]) -> Self {
+ var bb = BitBuffer([])
+ var accumData: UInt32 = 0
+ var accumCount: UInt32 = 0
+ for c in text {
+ guard let i = alphanumericCharset.firstIndex(of: c) else {
+ fatalError("String contains unencodable characters in alphanumeric mode")
+ }
+ accumData = accumData * 45 + UInt32(i)
+ accumCount += 1
+ if accumCount == 2 {
+ bb.appendBits(accumData, 11)
+ accumData = 0
+ accumCount = 0
+ }
+ }
+ if accumCount > 0 { // 1 character remaining
+ bb.appendBits(accumData, 6)
+ }
+ return QRSegment(mode: .alphanumeric, numChars: text.count, data: bb.bits)
+ }
+
+ /// Returns a list of zero or more segments to represent the given Unicode text string.
+ ///
+ /// The result may use various segment modes and switch
+ /// modes to optimize the length of the bit stream.
+ public static func makeSegments(text: [Character]) -> Self {
+ if text.isEmpty {
+ return []
+ } else if QRSegment.isNumeric(text) {
+ return [QRSegment.makeNumeric(text)]
+ } else if QRSegment.isAlphanumeric(text) {
+ return [QRSegment.makeAlphanumeric(text)]
+ } else {
+ let s = String(text)
+ return [QRSegment.makeBytes([UInt8](s.data(using: .utf8)!))]
+ }
+ }
+
+ /// Returns a segment representing an Extended Channel Interpretation
+ /// (ECI) designator with the given assignment value.
+ public static func makeECI(assignVal: UInt32) -> Self {
+ var bb = BitBuffer([])
+ if assignVal < (1 << 7) {
+ bb.appendBits(assignVal, 8)
+ } else if assignVal < (1 << 14) {
+ bb.appendBits(2, 2)
+ bb.appendBits(assignVal, 14)
+ } else if assignVal < 1_000_000 {
+ bb.appendBits(6, 3)
+ bb.appendBits(assignVal, 21)
+ } else {
+ fatalError("ECI assignment value out of range")
+ }
+ return QRSegment(mode: .eci, numChars: 0, data: bb.bits)
+ }
+}