From 48bf5a8b956ff9f696ce7ec2b3f4ecca3828cac1 Mon Sep 17 00:00:00 2001 From: Alan Zeino Date: Fri, 15 Mar 2019 15:28:41 -0700 Subject: [PATCH] swift5 --- Sources/SwiftProtobuf/AnyMessageStorage.swift | 36 +++--- Sources/SwiftProtobuf/BinaryDecoder.swift | 17 ++- Sources/SwiftProtobuf/BinaryDelimited.swift | 23 +++- Sources/SwiftProtobuf/Data+Extensions.swift | 33 +++++ .../Google_Protobuf_Any+Extensions.swift | 22 ++-- Sources/SwiftProtobuf/JSONEncoder.swift | 8 +- Sources/SwiftProtobuf/JSONScanner.swift | 95 ++++++++------ .../Message+BinaryAdditions.swift | 31 +++-- .../SwiftProtobuf/Message+JSONAdditions.swift | 32 +++-- .../Message+JSONArrayAdditions.swift | 17 ++- .../Message+TextFormatAdditions.swift | 19 +-- Sources/SwiftProtobuf/TextFormatEncoder.swift | 62 ++++----- .../TextFormatEncodingVisitor.swift | 15 ++- Sources/SwiftProtobuf/TextFormatScanner.swift | 122 +++++++++--------- SwiftProtobuf.xcodeproj/project.pbxproj | 10 ++ 15 files changed, 330 insertions(+), 212 deletions(-) create mode 100644 Sources/SwiftProtobuf/Data+Extensions.swift diff --git a/Sources/SwiftProtobuf/AnyMessageStorage.swift b/Sources/SwiftProtobuf/AnyMessageStorage.swift index 4e9c5c6fc..3eb842a63 100644 --- a/Sources/SwiftProtobuf/AnyMessageStorage.swift +++ b/Sources/SwiftProtobuf/AnyMessageStorage.swift @@ -66,22 +66,26 @@ fileprivate func unpack(contentJSON: Data, } var value = String() - try contentJSON.withUnsafeBytes { (bytes:UnsafePointer) in - let buffer = UnsafeBufferPointer(start: bytes, count: contentJSON.count) - var scanner = JSONScanner(source: buffer, - messageDepthLimit: options.messageDepthLimit, - ignoreUnknownFields: options.ignoreUnknownFields) - let key = try scanner.nextQuotedString() - if key != "value" { - // The only thing within a WKT should be "value". - throw AnyUnpackError.malformedWellKnownTypeJSON - } - try scanner.skipRequiredColon() // Can't fail - value = try scanner.skip() - if !scanner.complete { - // If that wasn't the end, then there was another key, - // and WKTs should only have the one. - throw AnyUnpackError.malformedWellKnownTypeJSON + try contentJSON.withUnsafeBytes { (body: UnsafeRawBufferPointer) in + if let baseAddress = body.baseAddress, body.count > 0 { + let bytes = baseAddress.assumingMemoryBound(to: UInt8.self) + + let buffer = UnsafeBufferPointer(start: bytes, count: body.count) + var scanner = JSONScanner(source: buffer, + messageDepthLimit: options.messageDepthLimit, + ignoreUnknownFields: options.ignoreUnknownFields) + let key = try scanner.nextQuotedString() + if key != "value" { + // The only thing within a WKT should be "value". + throw AnyUnpackError.malformedWellKnownTypeJSON + } + try scanner.skipRequiredColon() // Can't fail + value = try scanner.skip() + if !scanner.complete { + // If that wasn't the end, then there was another key, + // and WKTs should only have the one. + throw AnyUnpackError.malformedWellKnownTypeJSON + } } } return try messageType.init(jsonString: value, options: options) diff --git a/Sources/SwiftProtobuf/BinaryDecoder.swift b/Sources/SwiftProtobuf/BinaryDecoder.swift index ae68a033a..53144d052 100644 --- a/Sources/SwiftProtobuf/BinaryDecoder.swift +++ b/Sources/SwiftProtobuf/BinaryDecoder.swift @@ -876,13 +876,16 @@ internal struct BinaryDecoder: Decoder { } let fieldSize = Varint.encodedSize(of: fieldTag.rawValue) + Varint.encodedSize(of: Int64(bodySize)) + bodySize var field = Data(count: fieldSize) - field.withUnsafeMutableBytes { (pointer: UnsafeMutablePointer) in + field.withUnsafeMutableBytes { (body: UnsafeMutableRawBufferPointer) in + if let baseAddress = body.baseAddress, body.count > 0 { + let pointer = baseAddress.assumingMemoryBound(to: UInt8.self) var encoder = BinaryEncoder(forWritingInto: pointer) encoder.startField(tag: fieldTag) encoder.putVarInt(value: Int64(bodySize)) for v in extras { encoder.putVarInt(value: Int64(v)) } + } } unknownOverride = field } @@ -1204,9 +1207,11 @@ internal struct BinaryDecoder: Decoder { // If there already was fieldData, decode it. if let data = fieldData { var wasDecoded = false - try data.withUnsafeBytes { (pointer: UnsafePointer) in + try data.withUnsafeBytes { (body: UnsafeRawBufferPointer) in + if let baseAddress = body.baseAddress, body.count > 0 { + let pointer = baseAddress.assumingMemoryBound(to: UInt8.self) var extDecoder = BinaryDecoder(forReadingFrom: pointer, - count: data.count, + count: body.count, parent: self) // Prime the decode to be correct. extDecoder.consumed = false @@ -1216,6 +1221,7 @@ internal struct BinaryDecoder: Decoder { fieldNumber: fieldNumber, messageExtension: ext) wasDecoded = extDecoder.consumed + } } if !wasDecoded { return .malformed @@ -1245,9 +1251,12 @@ internal struct BinaryDecoder: Decoder { // Save it as length delimited let payloadSize = Varint.encodedSize(of: Int64(data.count)) + data.count var payload = Data(count: payloadSize) - payload.withUnsafeMutableBytes { (pointer: UnsafeMutablePointer) in + payload.withUnsafeMutableBytes { (body: UnsafeMutableRawBufferPointer) in + if let baseAddress = body.baseAddress, body.count > 0 { + let pointer = baseAddress.assumingMemoryBound(to: UInt8.self) var encoder = BinaryEncoder(forWritingInto: pointer) encoder.putBytesValue(value: data) + } } fieldData = payload } else { diff --git a/Sources/SwiftProtobuf/BinaryDelimited.swift b/Sources/SwiftProtobuf/BinaryDelimited.swift index d62e3afda..25420a63b 100644 --- a/Sources/SwiftProtobuf/BinaryDelimited.swift +++ b/Sources/SwiftProtobuf/BinaryDelimited.swift @@ -55,14 +55,20 @@ public enum BinaryDelimited { let serialized = try message.serializedData(partial: partial) let totalSize = Varint.encodedSize(of: UInt64(serialized.count)) + serialized.count var data = Data(count: totalSize) - data.withUnsafeMutableBytes { (pointer: UnsafeMutablePointer) in - var encoder = BinaryEncoder(forWritingInto: pointer) - encoder.putBytesValue(value: serialized) + data.withUnsafeMutableBytes { (body: UnsafeMutableRawBufferPointer) in + if let baseAddress = body.baseAddress, body.count > 0 { + let pointer = baseAddress.assumingMemoryBound(to: UInt8.self) + var encoder = BinaryEncoder(forWritingInto: pointer) + encoder.putBytesValue(value: serialized) + } } var written: Int = 0 - data.withUnsafeBytes { (pointer: UnsafePointer) in - written = stream.write(pointer, maxLength: totalSize) + data.withUnsafeBytes { (body: UnsafeRawBufferPointer) in + if let baseAddress = body.baseAddress, body.count > 0 { + let pointer = baseAddress.assumingMemoryBound(to: UInt8.self) + written = stream.write(pointer, maxLength: totalSize) + } } if written != totalSize { @@ -154,8 +160,11 @@ public enum BinaryDelimited { var data = Data(count: length) var bytesRead: Int = 0 - data.withUnsafeMutableBytes { (pointer: UnsafeMutablePointer) in - bytesRead = stream.read(pointer, maxLength: length) + data.withUnsafeMutableBytes { (body: UnsafeMutableRawBufferPointer) in + if let baseAddress = body.baseAddress, body.count > 0 { + let pointer = baseAddress.assumingMemoryBound(to: UInt8.self) + bytesRead = stream.read(pointer, maxLength: length) + } } if bytesRead != length { diff --git a/Sources/SwiftProtobuf/Data+Extensions.swift b/Sources/SwiftProtobuf/Data+Extensions.swift new file mode 100644 index 000000000..5b4e9a8bd --- /dev/null +++ b/Sources/SwiftProtobuf/Data+Extensions.swift @@ -0,0 +1,33 @@ +// Sources/SwiftProtobuf/Data+Extensions.swift - Extension exposing new Data API +// +// Copyright (c) 2014 - 2019 Apple Inc. and the project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See LICENSE.txt for license information: +// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt +// +// ----------------------------------------------------------------------------- +/// +/// Extension exposing new Data API to Swift versions < 5.0. +/// +// ----------------------------------------------------------------------------- + +import Foundation + +#if !swift(>=5.0) +internal extension Data { + func withUnsafeBytes(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T { + let c = count + return try withUnsafeBytes { (p: UnsafePointer) throws -> T in + try body(UnsafeRawBufferPointer(start: p, count: c)) + } + } + + mutating func withUnsafeMutableBytes(_ body: (UnsafeMutableRawBufferPointer) throws -> T) rethrows -> T { + let c = count + return try withUnsafeMutableBytes { (p: UnsafeMutablePointer) throws -> T in + try body(UnsafeMutableRawBufferPointer(start: p, count: c)) + } + } +} +#endif diff --git a/Sources/SwiftProtobuf/Google_Protobuf_Any+Extensions.swift b/Sources/SwiftProtobuf/Google_Protobuf_Any+Extensions.swift index 07bf39d96..d60774459 100644 --- a/Sources/SwiftProtobuf/Google_Protobuf_Any+Extensions.swift +++ b/Sources/SwiftProtobuf/Google_Protobuf_Any+Extensions.swift @@ -66,15 +66,19 @@ extension Google_Protobuf_Any { self.init() if !textFormatString.isEmpty { if let data = textFormatString.data(using: String.Encoding.utf8) { - try data.withUnsafeBytes { (bytes: UnsafePointer) in - var textDecoder = try TextFormatDecoder( - messageType: Google_Protobuf_Any.self, - utf8Pointer: bytes, - count: data.count, - extensions: extensions) - try decodeTextFormat(decoder: &textDecoder) - if !textDecoder.complete { - throw TextFormatDecodingError.trailingGarbage + try data.withUnsafeBytes { (body: UnsafeRawBufferPointer) in + if let baseAddress = body.baseAddress, body.count > 0 { + let bytes = baseAddress.assumingMemoryBound(to: UInt8.self) + + var textDecoder = try TextFormatDecoder( + messageType: Google_Protobuf_Any.self, + utf8Pointer: bytes, + count: body.count, + extensions: extensions) + try decodeTextFormat(decoder: &textDecoder) + if !textDecoder.complete { + throw TextFormatDecodingError.trailingGarbage + } } } } diff --git a/Sources/SwiftProtobuf/JSONEncoder.swift b/Sources/SwiftProtobuf/JSONEncoder.swift index d1bdb2a0c..200278733 100644 --- a/Sources/SwiftProtobuf/JSONEncoder.swift +++ b/Sources/SwiftProtobuf/JSONEncoder.swift @@ -333,10 +333,13 @@ internal struct JSONEncoder { internal mutating func putBytesValue(value: Data) { data.append(asciiDoubleQuote) if value.count > 0 { - value.withUnsafeBytes { (p: UnsafePointer) in + value.withUnsafeBytes { (body: UnsafeRawBufferPointer) in + if let baseAddress = body.baseAddress, body.count > 0 { + let p = baseAddress.assumingMemoryBound(to: UInt8.self) + var t: Int = 0 var bytesInGroup: Int = 0 - for i in 0..> 18) & 63]) data.append(base64Digits[(t >> 12) & 63]) @@ -369,6 +372,7 @@ internal struct JSONEncoder { default: break } + } } } data.append(asciiDoubleQuote) diff --git a/Sources/SwiftProtobuf/JSONScanner.swift b/Sources/SwiftProtobuf/JSONScanner.swift index 604e6be52..fc3728a39 100644 --- a/Sources/SwiftProtobuf/JSONScanner.swift +++ b/Sources/SwiftProtobuf/JSONScanner.swift @@ -190,8 +190,9 @@ private func parseBytes( // a closing double quote. index = digitsStart try value.withUnsafeMutableBytes { - (dataPointer: UnsafeMutablePointer) in - var p = dataPointer + (body: UnsafeMutableRawBufferPointer) in + if let baseAddress = body.baseAddress, body.count > 0 { + var p = baseAddress.assumingMemoryBound(to: UInt8.self) var n = 0 var chars = 0 // # chars in current group var padding = 0 // # padding '=' chars @@ -201,7 +202,6 @@ private func parseBytes( if k < 0 { switch digit { case asciiDoubleQuote: - source.formIndex(after: &index) break digits case asciiBackslash: source.formIndex(after: &index) @@ -221,7 +221,6 @@ private func parseBytes( while true { switch source[index] { case asciiDoubleQuote: - source.formIndex(after: &index) break digits case asciiSpace: break @@ -269,7 +268,9 @@ private func parseBytes( break } throw JSONDecodingError.malformedString + } } + source.formIndex(after: &index) return value } @@ -848,15 +849,18 @@ internal struct JSONScanner { let s = try nextQuotedString() let raw = s.data(using: String.Encoding.utf8)! let n = try raw.withUnsafeBytes { - (bytes: UnsafePointer) -> UInt64? in - let buffer = UnsafeBufferPointer(start: bytes, count: raw.count) - var index = buffer.startIndex - let end = buffer.endIndex - if let u = try parseBareUInt64(source: buffer, - index: &index, - end: end) { - if index == end { - return u + (body: UnsafeRawBufferPointer) -> UInt64? in + if let baseAddress = body.baseAddress, body.count > 0 { + let bytes = baseAddress.assumingMemoryBound(to: UInt8.self) + let buffer = UnsafeBufferPointer(start: bytes, count: body.count) + var index = buffer.startIndex + let end = buffer.endIndex + if let u = try parseBareUInt64(source: buffer, + index: &index, + end: end) { + if index == end { + return u + } } } return nil @@ -907,15 +911,18 @@ internal struct JSONScanner { let s = try nextQuotedString() let raw = s.data(using: String.Encoding.utf8)! let n = try raw.withUnsafeBytes { - (bytes: UnsafePointer) -> Int64? in - let buffer = UnsafeBufferPointer(start: bytes, count: raw.count) - var index = buffer.startIndex - let end = buffer.endIndex - if let s = try parseBareSInt64(source: buffer, - index: &index, - end: end) { - if index == end { - return s + (body: UnsafeRawBufferPointer) -> Int64? in + if let baseAddress = body.baseAddress, body.count > 0 { + let bytes = baseAddress.assumingMemoryBound(to: UInt8.self) + let buffer = UnsafeBufferPointer(start: bytes, count: body.count) + var index = buffer.startIndex + let end = buffer.endIndex + if let s = try parseBareSInt64(source: buffer, + index: &index, + end: end) { + if index == end { + return s + } } } return nil @@ -971,16 +978,19 @@ internal struct JSONScanner { default: let raw = s.data(using: String.Encoding.utf8)! let n = try raw.withUnsafeBytes { - (bytes: UnsafePointer) -> Float? in - let buffer = UnsafeBufferPointer(start: bytes, count: raw.count) - var index = buffer.startIndex - let end = buffer.endIndex - if let d = try parseBareDouble(source: buffer, - index: &index, - end: end) { - let f = Float(d) - if index == end && f.isFinite { - return f + (body: UnsafeRawBufferPointer) -> Float? in + if let baseAddress = body.baseAddress, body.count > 0 { + let bytes = baseAddress.assumingMemoryBound(to: UInt8.self) + let buffer = UnsafeBufferPointer(start: bytes, count: body.count) + var index = buffer.startIndex + let end = buffer.endIndex + if let d = try parseBareDouble(source: buffer, + index: &index, + end: end) { + let f = Float(d) + if index == end && f.isFinite { + return f + } } } return nil @@ -1042,15 +1052,18 @@ internal struct JSONScanner { default: let raw = s.data(using: String.Encoding.utf8)! let n = try raw.withUnsafeBytes { - (bytes: UnsafePointer) -> Double? in - let buffer = UnsafeBufferPointer(start: bytes, count: raw.count) - var index = buffer.startIndex - let end = buffer.endIndex - if let d = try parseBareDouble(source: buffer, - index: &index, - end: end) { - if index == end { - return d + (body: UnsafeRawBufferPointer) -> Double? in + if let baseAddress = body.baseAddress, body.count > 0 { + let bytes = baseAddress.assumingMemoryBound(to: UInt8.self) + let buffer = UnsafeBufferPointer(start: bytes, count: body.count) + var index = buffer.startIndex + let end = buffer.endIndex + if let d = try parseBareDouble(source: buffer, + index: &index, + end: end) { + if index == end { + return d + } } } return nil diff --git a/Sources/SwiftProtobuf/Message+BinaryAdditions.swift b/Sources/SwiftProtobuf/Message+BinaryAdditions.swift index 0de97d625..dd576171b 100644 --- a/Sources/SwiftProtobuf/Message+BinaryAdditions.swift +++ b/Sources/SwiftProtobuf/Message+BinaryAdditions.swift @@ -33,12 +33,16 @@ extension Message { } let requiredSize = try serializedDataSize() var data = Data(count: requiredSize) - try data.withUnsafeMutableBytes { (pointer: UnsafeMutablePointer) in - var visitor = BinaryEncodingVisitor(forWritingInto: pointer) - try traverse(visitor: &visitor) - // Currently not exposing this from the api because it really would be - // an internal error in the library and should never happen. - assert(requiredSize == visitor.encoder.distance(pointer: pointer)) + try data.withUnsafeMutableBytes { (body: UnsafeMutableRawBufferPointer) in + if let baseAddress = body.baseAddress, body.count > 0 { + let pointer = baseAddress.assumingMemoryBound(to: UInt8.self) + + var visitor = BinaryEncodingVisitor(forWritingInto: pointer) + try traverse(visitor: &visitor) + // Currently not exposing this from the api because it really would be + // an internal error in the library and should never happen. + assert(requiredSize == visitor.encoder.distance(pointer: pointer)) + } } return data } @@ -104,12 +108,15 @@ extension Message { options: BinaryDecodingOptions = BinaryDecodingOptions() ) throws { if !data.isEmpty { - try data.withUnsafeBytes { (pointer: UnsafePointer) in - var decoder = BinaryDecoder(forReadingFrom: pointer, - count: data.count, - options: options, - extensions: extensions) - try decoder.decodeFullMessage(message: &self) + try data.withUnsafeBytes { (body: UnsafeRawBufferPointer) in + if let baseAddress = body.baseAddress, body.count > 0 { + let pointer = baseAddress.assumingMemoryBound(to: UInt8.self) + var decoder = BinaryDecoder(forReadingFrom: pointer, + count: body.count, + options: options, + extensions: extensions) + try decoder.decodeFullMessage(message: &self) + } } } if !partial && !isInitialized { diff --git a/Sources/SwiftProtobuf/Message+JSONAdditions.swift b/Sources/SwiftProtobuf/Message+JSONAdditions.swift index df3a7abaf..5dbacf0c1 100644 --- a/Sources/SwiftProtobuf/Message+JSONAdditions.swift +++ b/Sources/SwiftProtobuf/Message+JSONAdditions.swift @@ -89,21 +89,25 @@ extension Message { options: JSONDecodingOptions = JSONDecodingOptions() ) throws { self.init() - try jsonUTF8Data.withUnsafeBytes { (bytes:UnsafePointer) in - let buffer = UnsafeBufferPointer(start: bytes, count: jsonUTF8Data.count) - var decoder = JSONDecoder(source: buffer, options: options) - if !decoder.scanner.skipOptionalNull() { - try decoder.decodeFullObject(message: &self) - } else if Self.self is _CustomJSONCodable.Type { - if let message = try (Self.self as! _CustomJSONCodable.Type) - .decodedFromJSONNull() { - self = message as! Self - } else { - throw JSONDecodingError.illegalNull + try jsonUTF8Data.withUnsafeBytes { (body: UnsafeRawBufferPointer) in + if let baseAddress = body.baseAddress, body.count > 0 { + let bytes = baseAddress.assumingMemoryBound(to: UInt8.self) + + let buffer = UnsafeBufferPointer(start: bytes, count: body.count) + var decoder = JSONDecoder(source: buffer, options: options) + if !decoder.scanner.skipOptionalNull() { + try decoder.decodeFullObject(message: &self) + } else if Self.self is _CustomJSONCodable.Type { + if let message = try (Self.self as! _CustomJSONCodable.Type) + .decodedFromJSONNull() { + self = message as! Self + } else { + throw JSONDecodingError.illegalNull + } + } + if !decoder.scanner.complete { + throw JSONDecodingError.trailingGarbage } - } - if !decoder.scanner.complete { - throw JSONDecodingError.trailingGarbage } } } diff --git a/Sources/SwiftProtobuf/Message+JSONArrayAdditions.swift b/Sources/SwiftProtobuf/Message+JSONArrayAdditions.swift index 05501c73c..38bf9f353 100644 --- a/Sources/SwiftProtobuf/Message+JSONArrayAdditions.swift +++ b/Sources/SwiftProtobuf/Message+JSONArrayAdditions.swift @@ -91,14 +91,19 @@ extension Message { fromJSONUTF8Data jsonUTF8Data: Data, options: JSONDecodingOptions = JSONDecodingOptions() ) throws -> [Self] { - return try jsonUTF8Data.withUnsafeBytes { (bytes:UnsafePointer) in + return try jsonUTF8Data.withUnsafeBytes { (body: UnsafeRawBufferPointer) in var array = [Self]() - let buffer = UnsafeBufferPointer(start: bytes, count: jsonUTF8Data.count) - var decoder = JSONDecoder(source: buffer, options: options) - try decoder.decodeRepeatedMessageField(value: &array) - if !decoder.scanner.complete { - throw JSONDecodingError.trailingGarbage + + if let baseAddress = body.baseAddress, body.count > 0 { + let bytes = baseAddress.assumingMemoryBound(to: UInt8.self) + let buffer = UnsafeBufferPointer(start: bytes, count: body.count) + var decoder = JSONDecoder(source: buffer, options: options) + try decoder.decodeRepeatedMessageField(value: &array) + if !decoder.scanner.complete { + throw JSONDecodingError.trailingGarbage + } } + return array } } diff --git a/Sources/SwiftProtobuf/Message+TextFormatAdditions.swift b/Sources/SwiftProtobuf/Message+TextFormatAdditions.swift index d9e2f5fb9..19b837098 100644 --- a/Sources/SwiftProtobuf/Message+TextFormatAdditions.swift +++ b/Sources/SwiftProtobuf/Message+TextFormatAdditions.swift @@ -70,14 +70,17 @@ extension Message { self.init() if !textFormatString.isEmpty { if let data = textFormatString.data(using: String.Encoding.utf8) { - try data.withUnsafeBytes { (bytes: UnsafePointer) in - var decoder = try TextFormatDecoder(messageType: Self.self, - utf8Pointer: bytes, - count: data.count, - extensions: extensions) - try decodeMessage(decoder: &decoder) - if !decoder.complete { - throw TextFormatDecodingError.trailingGarbage + try data.withUnsafeBytes { (body: UnsafeRawBufferPointer) in + if let baseAddress = body.baseAddress, body.count > 0 { + let bytes = baseAddress.assumingMemoryBound(to: UInt8.self) + var decoder = try TextFormatDecoder(messageType: Self.self, + utf8Pointer: bytes, + count: body.count, + extensions: extensions) + try decodeMessage(decoder: &decoder) + if !decoder.complete { + throw TextFormatDecodingError.trailingGarbage + } } } } diff --git a/Sources/SwiftProtobuf/TextFormatEncoder.swift b/Sources/SwiftProtobuf/TextFormatEncoder.swift index dd25f7326..fd758fd8c 100644 --- a/Sources/SwiftProtobuf/TextFormatEncoder.swift +++ b/Sources/SwiftProtobuf/TextFormatEncoder.swift @@ -263,36 +263,40 @@ internal struct TextFormatEncoder { mutating func putBytesValue(value: Data) { data.append(asciiDoubleQuote) - value.withUnsafeBytes { (p: UnsafePointer) in - for i in 0.. 0 { + let p = baseAddress.assumingMemoryBound(to: UInt8.self) + + for i in 0..) -> () in + try bytes.withUnsafeBytes { (body: UnsafeRawBufferPointer) -> () in + if let baseAddress = body.baseAddress, body.count > 0 { + let p = baseAddress.assumingMemoryBound(to: UInt8.self) var decoder = BinaryDecoder(forReadingFrom: p, - count: bytes.count, + count: body.count, options: BinaryDecodingOptions()) try visitUnknown(decoder: &decoder, groupFieldNumber: nil) + } } } } @@ -107,9 +110,12 @@ internal struct TextFormatEncodingVisitor: Visitor { encoder.emitFieldNumber(number: tag.fieldNumber) var bytes = Internal.emptyData try decoder.decodeSingularBytesField(value: &bytes) - bytes.withUnsafeBytes { (p: UnsafePointer) -> () in + bytes.withUnsafeBytes { (body: UnsafeRawBufferPointer) -> () in + if let baseAddress = body.baseAddress, body.count > 0 { + let p = baseAddress.assumingMemoryBound(to: UInt8.self) + var testDecoder = BinaryDecoder(forReadingFrom: p, - count: bytes.count, + count: body.count, parent: decoder) do { // Skip all the fields to test if it looks like a message @@ -128,6 +134,7 @@ internal struct TextFormatEncodingVisitor: Visitor { encoder.putBytesValue(value: bytes) encoder.endRegularField() } + } } case .startGroup: encoder.emitFieldNumber(number: tag.fieldNumber) diff --git a/Sources/SwiftProtobuf/TextFormatScanner.swift b/Sources/SwiftProtobuf/TextFormatScanner.swift index 137afdeae..e03a30214 100644 --- a/Sources/SwiftProtobuf/TextFormatScanner.swift +++ b/Sources/SwiftProtobuf/TextFormatScanner.swift @@ -356,78 +356,80 @@ internal struct TextFormatScanner { /// verified the correctness. So we get to avoid error checks here. private mutating func parseBytesFromString(terminator: UInt8, into data: inout Data) { data.withUnsafeMutableBytes { - (dataPointer: UnsafeMutablePointer) in - var out = dataPointer - while p[0] != terminator { - let byte = p[0] - p += 1 - switch byte { - case asciiBackslash: // "\\" - let escaped = p[0] + (body: UnsafeMutableRawBufferPointer) in + if let baseAddress = body.baseAddress, body.count > 0 { + var out = baseAddress.assumingMemoryBound(to: UInt8.self) + while p[0] != terminator { + let byte = p[0] p += 1 - switch escaped { - case asciiZero...asciiSeven: // '0'...'7' - // C standard allows 1, 2, or 3 octal digits. - let digit1Value = escaped - asciiZero - let digit2 = p[0] - if digit2 >= asciiZero, digit2 <= asciiSeven { - p += 1 - let digit2Value = digit2 - asciiZero - let digit3 = p[0] - if digit3 >= asciiZero, digit3 <= asciiSeven { + switch byte { + case asciiBackslash: // "\\" + let escaped = p[0] + p += 1 + switch escaped { + case asciiZero...asciiSeven: // '0'...'7' + // C standard allows 1, 2, or 3 octal digits. + let digit1Value = escaped - asciiZero + let digit2 = p[0] + if digit2 >= asciiZero, digit2 <= asciiSeven { p += 1 - let digit3Value = digit3 - asciiZero - out[0] = digit1Value &* 64 + digit2Value * 8 + digit3Value - out += 1 + let digit2Value = digit2 - asciiZero + let digit3 = p[0] + if digit3 >= asciiZero, digit3 <= asciiSeven { + p += 1 + let digit3Value = digit3 - asciiZero + out[0] = digit1Value &* 64 + digit2Value * 8 + digit3Value + out += 1 + } else { + out[0] = digit1Value * 8 + digit2Value + out += 1 + } } else { - out[0] = digit1Value * 8 + digit2Value + out[0] = digit1Value out += 1 } - } else { - out[0] = digit1Value - out += 1 - } - case asciiLowerX: // 'x' hexadecimal escape - // We already validated, so we know there's at least one digit: - var n = fromHexDigit(p[0])! - p += 1 - if let digit = fromHexDigit(p[0]) { - n = n &* 16 &+ digit + case asciiLowerX: // 'x' hexadecimal escape + // We already validated, so we know there's at least one digit: + var n = fromHexDigit(p[0])! p += 1 + if let digit = fromHexDigit(p[0]) { + n = n &* 16 &+ digit + p += 1 + } + out[0] = n + out += 1 + case asciiLowerA: // \a ("alert") + out[0] = asciiBell + out += 1 + case asciiLowerB: // \b + out[0] = asciiBackspace + out += 1 + case asciiLowerF: // \f + out[0] = asciiFormFeed + out += 1 + case asciiLowerN: // \n + out[0] = asciiNewLine + out += 1 + case asciiLowerR: // \r + out[0] = asciiCarriageReturn + out += 1 + case asciiLowerT: // \t + out[0] = asciiTab + out += 1 + case asciiLowerV: // \v + out[0] = asciiVerticalTab + out += 1 + default: + out[0] = escaped + out += 1 } - out[0] = n - out += 1 - case asciiLowerA: // \a ("alert") - out[0] = asciiBell - out += 1 - case asciiLowerB: // \b - out[0] = asciiBackspace - out += 1 - case asciiLowerF: // \f - out[0] = asciiFormFeed - out += 1 - case asciiLowerN: // \n - out[0] = asciiNewLine - out += 1 - case asciiLowerR: // \r - out[0] = asciiCarriageReturn - out += 1 - case asciiLowerT: // \t - out[0] = asciiTab - out += 1 - case asciiLowerV: // \v - out[0] = asciiVerticalTab - out += 1 default: - out[0] = escaped + out[0] = byte out += 1 } - default: - out[0] = byte - out += 1 } + p += 1 // Consume terminator } - p += 1 // Consume terminator } } diff --git a/SwiftProtobuf.xcodeproj/project.pbxproj b/SwiftProtobuf.xcodeproj/project.pbxproj index dbfe818bd..4ff5ec0ba 100644 --- a/SwiftProtobuf.xcodeproj/project.pbxproj +++ b/SwiftProtobuf.xcodeproj/project.pbxproj @@ -288,6 +288,10 @@ DB2E0AFF1EB25D1D00F59319 /* Message+JSONArrayAdditions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB2E0AFD1EB25D1D00F59319 /* Message+JSONArrayAdditions.swift */; }; DB2E0B001EB25D1D00F59319 /* Message+JSONArrayAdditions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB2E0AFD1EB25D1D00F59319 /* Message+JSONArrayAdditions.swift */; }; DB2E0B011EB25D1D00F59319 /* Message+JSONArrayAdditions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB2E0AFD1EB25D1D00F59319 /* Message+JSONArrayAdditions.swift */; }; + E7038A24224D7F1000B68775 /* Data+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7038A23224D7F1000B68775 /* Data+Extensions.swift */; }; + E7038A25224D7F1000B68775 /* Data+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7038A23224D7F1000B68775 /* Data+Extensions.swift */; }; + E7038A26224D7F1000B68775 /* Data+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7038A23224D7F1000B68775 /* Data+Extensions.swift */; }; + E7038A27224D7F1000B68775 /* Data+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7038A23224D7F1000B68775 /* Data+Extensions.swift */; }; ECBC5C491DF6ABC500F658E8 /* Google_Protobuf_Wrappers+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAEA52711DA80DD4003F318F /* Google_Protobuf_Wrappers+Extensions.swift */; }; ECBC5C4A1DF6ABC500F658E8 /* Google_Protobuf_Struct+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = __PBXFileRef_Sources/Protobuf/Google_Protobuf_Struct.swift /* Google_Protobuf_Struct+Extensions.swift */; }; ECBC5C4B1DF6ABC500F658E8 /* timestamp.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = __PBXFileRef_Sources/Protobuf/timestamp.pb.swift /* timestamp.pb.swift */; }; @@ -738,6 +742,7 @@ BCCA0E751DB123F800957D74 /* Test_TextFormat_proto3.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Test_TextFormat_proto3.swift; sourceTree = ""; }; DB2E0AF91EB24C7600F59319 /* Test_JSON_Array.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Test_JSON_Array.swift; sourceTree = ""; }; DB2E0AFD1EB25D1D00F59319 /* Message+JSONArrayAdditions.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = "Message+JSONArrayAdditions.swift"; sourceTree = ""; tabWidth = 2; }; + E7038A23224D7F1000B68775 /* Data+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+Extensions.swift"; sourceTree = ""; }; F40D33E82017ECD300ABAF0F /* unittest_swift_enum_proto3.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = unittest_swift_enum_proto3.pb.swift; sourceTree = ""; }; F411FE941EDDD6AA001AE6B2 /* BinaryDecodingOptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinaryDecodingOptions.swift; sourceTree = ""; }; F411FEAA1EDDDC5D001AE6B2 /* Test_BinaryDecodingOptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Test_BinaryDecodingOptions.swift; sourceTree = ""; }; @@ -969,6 +974,7 @@ AA28A4AB1DA454DA00C866D9 /* BinaryEncodingSizeVisitor.swift */, 9C75F8931DDD3D20005CCFF2 /* BinaryEncodingVisitor.swift */, F4539D291E6F5DC70076251F /* CustomJSONCodable.swift */, + E7038A23224D7F1000B68775 /* Data+Extensions.swift */, __PBXFileRef_Sources/Protobuf/ProtobufFieldDecoder.swift /* Decoder.swift */, 9C1BD4BE1E7C51FB0064CD53 /* DoubleFormatter.swift */, __PBXFileRef_Sources/Protobuf/duration.pb.swift /* duration.pb.swift */, @@ -1496,6 +1502,7 @@ 9C1BD4C01E7C51FB0064CD53 /* DoubleFormatter.swift in Sources */, AA86F6FB1E0A0F0B006CC38A /* JSONEncodingVisitor.swift in Sources */, F41BA4141E79BE54004F6E95 /* Google_Protobuf_Any+Extensions.swift in Sources */, + E7038A25224D7F1000B68775 /* Data+Extensions.swift in Sources */, 9C2F238C1D7780D1008524F2 /* MessageExtension.swift in Sources */, 9C667A961E4C203D008B974F /* BinaryDecodingError.swift in Sources */, 9C2F238D1D7780D1008524F2 /* Decoder.swift in Sources */, @@ -1581,6 +1588,7 @@ 9C84E4931E5E3ABD00513BE0 /* JSONEncodingError.swift in Sources */, 9C1BD4BF1E7C51FB0064CD53 /* DoubleFormatter.swift in Sources */, 8DC1CA0D1E54B80800CA8A26 /* MathUtils.swift in Sources */, + E7038A24224D7F1000B68775 /* Data+Extensions.swift in Sources */, F41BA4131E79BDCA004F6E95 /* Google_Protobuf_Any+Extensions.swift in Sources */, AAEA52721DA80DD4003F318F /* Google_Protobuf_Wrappers+Extensions.swift in Sources */, AAABA40B1E4A42CD00365CDF /* ProtobufAPIVersionCheck.swift in Sources */, @@ -1784,6 +1792,7 @@ 9C84E4951E5E3ABD00513BE0 /* JSONEncodingError.swift in Sources */, 9C1BD4C11E7C51FB0064CD53 /* DoubleFormatter.swift in Sources */, F4F4F11F1E5C7563006C6CAD /* MathUtils.swift in Sources */, + E7038A26224D7F1000B68775 /* Data+Extensions.swift in Sources */, F41BA4151E79BE55004F6E95 /* Google_Protobuf_Any+Extensions.swift in Sources */, F44F937E1DAEA76700BC5B85 /* Google_Protobuf_Struct+Extensions.swift in Sources */, 9C667A971E4C203D008B974F /* BinaryDecodingError.swift in Sources */, @@ -1987,6 +1996,7 @@ 9C84E4961E5E3ABD00513BE0 /* JSONEncodingError.swift in Sources */, 9C1BD4C21E7C51FB0064CD53 /* DoubleFormatter.swift in Sources */, ECBC5C491DF6ABC500F658E8 /* Google_Protobuf_Wrappers+Extensions.swift in Sources */, + E7038A27224D7F1000B68775 /* Data+Extensions.swift in Sources */, F41BA4161E79BE56004F6E95 /* Google_Protobuf_Any+Extensions.swift in Sources */, AA86F6FD1E0A0F0B006CC38A /* JSONEncodingVisitor.swift in Sources */, 9C667A981E4C203D008B974F /* BinaryDecodingError.swift in Sources */,