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
20require 'TProtocol'
21require 'libluabpack'
22require 'libluabitwise'
23
24TBinaryProtocol = __TObject.new(TProtocolBase, {
25  __type = 'TBinaryProtocol',
26  VERSION_MASK = -65536, -- 0xffff0000
27  VERSION_1    = -2147418112, -- 0x80010000
28  TYPE_MASK    = 0x000000ff,
29  strictRead   = false,
30  strictWrite  = true
31})
32
33function TBinaryProtocol:writeMessageBegin(name, ttype, seqid)
34  if self.strictWrite then
35    self:writeI32(libluabitwise.bor(TBinaryProtocol.VERSION_1, ttype))
36    self:writeString(name)
37    self:writeI32(seqid)
38  else
39    self:writeString(name)
40    self:writeByte(ttype)
41    self:writeI32(seqid)
42  end
43end
44
45function TBinaryProtocol:writeMessageEnd()
46end
47
48function TBinaryProtocol:writeStructBegin(name)
49end
50
51function TBinaryProtocol:writeStructEnd()
52end
53
54function TBinaryProtocol:writeFieldBegin(name, ttype, id)
55  self:writeByte(ttype)
56  self:writeI16(id)
57end
58
59function TBinaryProtocol:writeFieldEnd()
60end
61
62function TBinaryProtocol:writeFieldStop()
63  self:writeByte(TType.STOP);
64end
65
66function TBinaryProtocol:writeMapBegin(ktype, vtype, size)
67  self:writeByte(ktype)
68  self:writeByte(vtype)
69  self:writeI32(size)
70end
71
72function TBinaryProtocol:writeMapEnd()
73end
74
75function TBinaryProtocol:writeListBegin(etype, size)
76  self:writeByte(etype)
77  self:writeI32(size)
78end
79
80function TBinaryProtocol:writeListEnd()
81end
82
83function TBinaryProtocol:writeSetBegin(etype, size)
84  self:writeByte(etype)
85  self:writeI32(size)
86end
87
88function TBinaryProtocol:writeSetEnd()
89end
90
91function TBinaryProtocol:writeBool(bool)
92  if bool then
93    self:writeByte(1)
94  else
95    self:writeByte(0)
96  end
97end
98
99function TBinaryProtocol:writeByte(byte)
100  local buff = libluabpack.bpack('c', byte)
101  self.trans:write(buff)
102end
103
104function TBinaryProtocol:writeI16(i16)
105  local buff = libluabpack.bpack('s', i16)
106  self.trans:write(buff)
107end
108
109function TBinaryProtocol:writeI32(i32)
110  local buff = libluabpack.bpack('i', i32)
111  self.trans:write(buff)
112end
113
114function TBinaryProtocol:writeI64(i64)
115  local buff = libluabpack.bpack('l', i64)
116  self.trans:write(buff)
117end
118
119function TBinaryProtocol:writeDouble(dub)
120  local buff = libluabpack.bpack('d', dub)
121  self.trans:write(buff)
122end
123
124function TBinaryProtocol:writeString(str)
125  -- Should be utf-8
126  self:writeI32(string.len(str))
127  self.trans:write(str)
128end
129
130function TBinaryProtocol:readMessageBegin()
131  local sz, ttype, name, seqid = self:readI32()
132  if sz < 0 then
133    local version = libluabitwise.band(sz, TBinaryProtocol.VERSION_MASK)
134    if version ~= TBinaryProtocol.VERSION_1 then
135      terror(TProtocolException:new{
136        message = 'Bad version in readMessageBegin: ' .. sz
137      })
138    end
139    ttype = libluabitwise.band(sz, TBinaryProtocol.TYPE_MASK)
140    name = self:readString()
141    seqid = self:readI32()
142  else
143    if self.strictRead then
144      terror(TProtocolException:new{message = 'No protocol version header'})
145    end
146    name = self.trans:readAll(sz)
147    ttype = self:readByte()
148    seqid = self:readI32()
149  end
150  return name, ttype, seqid
151end
152
153function TBinaryProtocol:readMessageEnd()
154end
155
156function TBinaryProtocol:readStructBegin()
157  return nil
158end
159
160function TBinaryProtocol:readStructEnd()
161end
162
163function TBinaryProtocol:readFieldBegin()
164  local ttype = self:readByte()
165  if ttype == TType.STOP then
166    return nil, ttype, 0
167  end
168  local id = self:readI16()
169  return nil, ttype, id
170end
171
172function TBinaryProtocol:readFieldEnd()
173end
174
175function TBinaryProtocol:readMapBegin()
176  local ktype = self:readByte()
177  local vtype = self:readByte()
178  local size = self:readI32()
179  return ktype, vtype, size
180end
181
182function TBinaryProtocol:readMapEnd()
183end
184
185function TBinaryProtocol:readListBegin()
186  local etype = self:readByte()
187  local size = self:readI32()
188  return etype, size
189end
190
191function TBinaryProtocol:readListEnd()
192end
193
194function TBinaryProtocol:readSetBegin()
195  local etype = self:readByte()
196  local size = self:readI32()
197  return etype, size
198end
199
200function TBinaryProtocol:readSetEnd()
201end
202
203function TBinaryProtocol:readBool()
204  local byte = self:readByte()
205  if byte == 0 then
206    return false
207  end
208  return true
209end
210
211function TBinaryProtocol:readByte()
212  local buff = self.trans:readAll(1)
213  local val = libluabpack.bunpack('c', buff)
214  return val
215end
216
217function TBinaryProtocol:readI16()
218  local buff = self.trans:readAll(2)
219  local val = libluabpack.bunpack('s', buff)
220  return val
221end
222
223function TBinaryProtocol:readI32()
224  local buff = self.trans:readAll(4)
225  local val = libluabpack.bunpack('i', buff)
226  return val
227end
228
229function TBinaryProtocol:readI64()
230  local buff = self.trans:readAll(8)
231  local val = libluabpack.bunpack('l', buff)
232  return val
233end
234
235function TBinaryProtocol:readDouble()
236  local buff = self.trans:readAll(8)
237  local val = libluabpack.bunpack('d', buff)
238  return val
239end
240
241function TBinaryProtocol:readString()
242  local len = self:readI32()
243  local str = self.trans:readAll(len)
244  return str
245end
246
247TBinaryProtocolFactory = TProtocolFactory:new{
248  __type = 'TBinaryProtocolFactory',
249  strictRead = false
250}
251
252function TBinaryProtocolFactory:getProtocol(trans)
253  -- TODO Enforce that this must be a transport class (ie not a bool)
254  if not trans then
255    terror(TProtocolException:new{
256      message = 'Must supply a transport to ' .. ttype(self)
257    })
258  end
259  return TBinaryProtocol:new{
260    trans = trans,
261    strictRead = self.strictRead,
262    strictWrite = true
263  }
264end
265