1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 import Foundation
21 
22 public struct TBinaryProtocolVersion {
23   static let version1    = Int32(bitPattern: 0x80010000)
24   static let versionMask = Int32(bitPattern: 0xffff0000)
25 }
26 
27 public class TBinaryProtocol: TProtocol {
28   public var messageSizeLimit: UInt32  = 0
29 
30   public var transport: TTransport
31 
32   // class level properties for setting global config (useful for server in lieu of Factory design)
33   public static var strictRead: Bool = false
34   public static var strictWrite: Bool = true
35 
36   private var strictRead: Bool
37   private var strictWrite: Bool
38 
39   var currentMessageName: String?
40   var currentFieldName: String?
41 
42 
43   public convenience init(transport: TTransport, strictRead: Bool, strictWrite: Bool) {
44     self.init(on: transport)
45     self.strictRead = strictRead
46     self.strictWrite = strictWrite
47   }
48 
49   public required init(on transport: TTransport) {
50     self.transport = transport
51     self.strictWrite = TBinaryProtocol.strictWrite
52     self.strictRead = TBinaryProtocol.strictRead
53   }
54 
readStringBodynull55   func readStringBody(_ size: Int) throws -> String {
56 
57     var data = Data()
58     try ProtocolTransportTry(error: TProtocolError(message: "Transport read failed")) {
59       data = try self.transport.readAll(size: size)
60     }
61 
62     return String(data: data, encoding: String.Encoding.utf8) ?? ""
63   }
64 
65   /// Mark: - TProtocol
66 
readMessageBeginnull67   public func readMessageBegin() throws -> (String, TMessageType, Int32) {
68     let size: Int32 = try read()
69     var messageName = ""
70     var type = TMessageType.exception
71 
72     if size < 0 {
73       let version = size & TBinaryProtocolVersion.versionMask
74       if version != TBinaryProtocolVersion.version1 {
75         throw TProtocolError(error: .badVersion(expected: "\(TBinaryProtocolVersion.version1)",
76                                                 got: "\(version)"))
77       }
78       type = TMessageType(rawValue: Int32(size) & 0x00FF) ?? type
79       messageName = try read()
80     } else {
81       if strictRead {
82         let errorMessage = "Missing message version, old client? Message Name: \(currentMessageName ?? "")"
83         throw TProtocolError(error: .invalidData,
84                              message: errorMessage)
85       }
86       if messageSizeLimit > 0 && size > Int32(messageSizeLimit) {
87         throw TProtocolError(error: .sizeLimit(limit: Int(messageSizeLimit), got: Int(size)))
88       }
89 
90       messageName = try readStringBody(Int(size))
91       type = TMessageType(rawValue: Int32(try read() as UInt8)) ?? type
92     }
93 
94     let seqID: Int32 = try read()
95     return (messageName, type, seqID)
96   }
97 
readMessageEndnull98   public func readMessageEnd() throws {
99     return
100   }
101 
readStructBeginnull102   public func readStructBegin() throws -> String {
103     return ""
104   }
105 
readStructEndnull106   public func readStructEnd() throws {
107     return
108   }
109 
readFieldBeginnull110   public func readFieldBegin() throws -> (String, TType, Int32) {
111 
112     let fieldType = TType(rawValue: Int32(try read() as UInt8)) ?? TType.stop
113     var fieldID: Int32 = 0
114 
115     if fieldType != .stop {
116       fieldID = Int32(try read() as Int16)
117     }
118 
119     return ("", fieldType, fieldID)
120   }
121 
readFieldEndnull122   public func readFieldEnd() throws {
123     return
124   }
125 
readMapBeginnull126   public func readMapBegin() throws -> (TType, TType, Int32) {
127     var raw = Int32(try read() as UInt8)
128     guard let keyType = TType(rawValue: raw) else {
129       throw TProtocolError(message: "Unknown value for keyType TType: \(raw)")
130     }
131 
132     raw = Int32(try read() as UInt8)
133     guard let valueType = TType(rawValue: raw) else {
134       throw TProtocolError(message: "Unknown value for valueType TType: \(raw)")
135     }
136     let size: Int32 = try read()
137 
138     return (keyType, valueType, size)
139   }
140 
readMapEndnull141   public func readMapEnd() throws {
142     return
143   }
144 
readSetBeginnull145   public func readSetBegin() throws -> (TType, Int32) {
146     let raw = Int32(try read() as UInt8)
147     guard let elementType = TType(rawValue: raw) else {
148       throw TProtocolError(message: "Unknown value for elementType TType: \(raw)")
149     }
150 
151     let size: Int32 = try read()
152 
153     return (elementType, size)
154   }
155 
readSetEndnull156   public func readSetEnd() throws {
157     return
158   }
159 
readListBeginnull160   public func readListBegin() throws -> (TType, Int32) {
161     let raw = Int32(try read() as UInt8)
162     guard let elementType = TType(rawValue: raw) else {
163       throw TProtocolError(message: "Unknown value for elementType TType: \(raw)")
164     }
165     let size: Int32 = try read()
166 
167     return (elementType, size)
168   }
169 
readListEndnull170   public func readListEnd() throws {
171     return
172   }
173 
readnull174   public func read() throws -> String {
175     let data: Data = try read()
176     guard let str = String.init(data: data, encoding: .utf8) else {
177       throw TProtocolError(error: .invalidData, message: "Couldn't encode UTF-8 from data read")
178     }
179     return str
180   }
181 
readnull182   public func read() throws -> Bool {
183     return (try read() as UInt8) == 1
184   }
185 
readnull186   public func read() throws -> UInt8 {
187     var buff = Data()
188     try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
189       buff = try self.transport.readAll(size: 1)
190     }
191     return buff[0]
192   }
193 
readnull194   public func read() throws -> Int16 {
195     var buff = Data()
196     try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
197       buff = try self.transport.readAll(size: 2)
198     }
199     var ret = Int16(buff[0] & 0xff) << 8
200     ret |=    Int16(buff[1] & 0xff)
201     return ret
202   }
203 
readnull204   public func read() throws -> Int32 {
205     var buff = Data()
206     try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
207       buff = try self.transport.readAll(size: 4)
208     }
209     var ret = Int32(buff[0] & 0xff) << 24
210     ret |=    Int32(buff[1] & 0xff) << 16
211     ret |=    Int32(buff[2] & 0xff) << 8
212     ret |=    Int32(buff[3] & 0xff)
213 
214     return ret
215   }
216 
readnull217   public func read() throws -> Int64 {
218     var buff = Data()
219     try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
220       buff = try self.transport.readAll(size: 8)
221     }
222     var ret = Int64(buff[0] & 0xff) << 56
223     ret |=    Int64(buff[1] & 0xff) << 48
224     ret |=    Int64(buff[2] & 0xff) << 40
225     ret |=    Int64(buff[3] & 0xff) << 32
226     ret |=    Int64(buff[4] & 0xff) << 24
227     ret |=    Int64(buff[5] & 0xff) << 16
228     ret |=    Int64(buff[6] & 0xff) << 8
229     ret |=    Int64(buff[7] & 0xff)
230 
231     return ret
232   }
233 
readnull234   public func read() throws -> Double {
235     let val = try read() as Int64
236     return Double(bitPattern: UInt64(bitPattern: val))
237   }
238 
readnull239   public func read() throws -> Data {
240     let size = Int(try read() as Int32)
241     var data = Data()
242     try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
243       data = try self.transport.readAll(size: size)
244     }
245 
246     return data
247   }
248 
249   // Write methods
250 
writeMessageBeginnull251   public func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws {
252     if strictWrite {
253       let version = TBinaryProtocolVersion.version1 | Int32(messageType.rawValue)
254       try write(version)
255       try write(name)
256       try write(sequenceID)
257     } else {
258       try write(name)
259       try write(UInt8(messageType.rawValue))
260       try write(sequenceID)
261     }
262     currentMessageName = name
263   }
264 
writeMessageEndnull265   public func writeMessageEnd() throws {
266     currentMessageName = nil
267   }
268 
writeStructBeginnull269   public func writeStructBegin(name: String) throws {
270     return
271   }
272 
writeStructEndnull273   public func writeStructEnd() throws {
274     return
275   }
276 
writeFieldBeginnull277   public func writeFieldBegin(name: String, type fieldType: TType, fieldID: Int32) throws {
278     try write(UInt8(fieldType.rawValue))
279     try write(Int16(fieldID))
280   }
281 
writeFieldStopnull282   public func writeFieldStop() throws {
283     try write(UInt8(TType.stop.rawValue))
284   }
285 
writeFieldEndnull286   public func writeFieldEnd() throws {
287     return
288   }
289 
writeMapBeginnull290   public func writeMapBegin(keyType: TType, valueType: TType, size: Int32) throws {
291     try write(UInt8(keyType.rawValue))
292     try write(UInt8(valueType.rawValue))
293     try write(size)
294   }
295 
writeMapEndnull296   public func writeMapEnd() throws {
297     return
298   }
299 
writeSetBeginnull300   public func writeSetBegin(elementType: TType, size: Int32) throws {
301     try write(UInt8(elementType.rawValue))
302     try write(size)
303   }
304 
writeSetEndnull305   public func writeSetEnd() throws {
306     return
307   }
308 
writeListBeginnull309   public func writeListBegin(elementType: TType, size: Int32) throws {
310     try write(UInt8(elementType.rawValue))
311     try write(size)
312   }
313 
writeListEndnull314   public func writeListEnd() throws {
315     return
316   }
317 
writenull318   public func write(_ value: String) throws {
319     try write(value.data(using: .utf8)!)
320   }
321 
writenull322   public func write(_ value: Bool) throws {
323     let byteVal: UInt8 = value ? 1 : 0
324     try write(byteVal)
325   }
326 
writenull327   public func write(_ value: UInt8) throws {
328     let buff = Data([value])
329 
330     try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) {
331       try self.transport.write(data: buff)
332     }
333   }
334 
writenull335   public func write(_ value: Int16) throws {
336     var buff = Data()
337     buff.append(Data([UInt8(0xff & (value >> 8))]))
338     buff.append(Data([UInt8(0xff & (value))]))
339     try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) {
340       try self.transport.write(data: buff)
341     }
342   }
343 
writenull344   public func write(_ value: Int32) throws {
345     var buff = Data()
346     buff.append(Data([UInt8(0xff & (value >> 24))]))
347     buff.append(Data([UInt8(0xff & (value >> 16))]))
348     buff.append(Data([UInt8(0xff & (value >> 8))]))
349     buff.append(Data([UInt8(0xff & (value))]))
350 
351     try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) {
352       try self.transport.write(data: buff)
353     }
354   }
355 
writenull356   public func write(_ value: Int64) throws {
357     var buff = Data()
358     buff.append(Data([UInt8(0xff & (value >> 56))]))
359     buff.append(Data([UInt8(0xff & (value >> 48))]))
360     buff.append(Data([UInt8(0xff & (value >> 40))]))
361     buff.append(Data([UInt8(0xff & (value >> 32))]))
362     buff.append(Data([UInt8(0xff & (value >> 24))]))
363     buff.append(Data([UInt8(0xff & (value >> 16))]))
364     buff.append(Data([UInt8(0xff & (value >> 8))]))
365     buff.append(Data([UInt8(0xff & (value))]))
366 
367     try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) {
368       try self.transport.write(data: buff)
369     }
370   }
371 
writenull372   public func write(_ value: Double) throws {
373     // Notably unsafe, since Double and Int64 are the same size, this should work fine
374     try self.write(Int64(bitPattern: value.bitPattern))
375   }
376 
writenull377   public func write(_ data: Data) throws {
378     try write(Int32(data.count))
379 
380     try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) {
381       try self.transport.write(data: data)
382     }
383   }
384 }
385