]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
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 | require 'TProtocol' | |
21 | require 'libluabpack' | |
22 | require 'libluabitwise' | |
23 | require 'liblualongnumber' | |
24 | ||
25 | TCompactProtocol = __TObject.new(TProtocolBase, { | |
26 | __type = 'TCompactProtocol', | |
27 | COMPACT_PROTOCOL_ID = 0x82, | |
28 | COMPACT_VERSION = 1, | |
29 | COMPACT_VERSION_MASK = 0x1f, | |
30 | COMPACT_TYPE_MASK = 0xE0, | |
31 | COMPACT_TYPE_BITS = 0x07, | |
32 | COMPACT_TYPE_SHIFT_AMOUNT = 5, | |
33 | ||
34 | -- Used to keep track of the last field for the current and previous structs, | |
35 | -- so we can do the delta stuff. | |
36 | lastField = {}, | |
37 | lastFieldId = 0, | |
38 | lastFieldIndex = 1, | |
39 | ||
40 | -- If we encounter a boolean field begin, save the TField here so it can | |
41 | -- have the value incorporated. | |
42 | booleanFieldName = "", | |
43 | booleanFieldId = 0, | |
44 | booleanFieldPending = false, | |
45 | ||
46 | -- If we read a field header, and it's a boolean field, save the boolean | |
47 | -- value here so that readBool can use it. | |
48 | boolValue = false, | |
49 | boolValueIsNotNull = false, | |
50 | }) | |
51 | ||
52 | TCompactType = { | |
53 | COMPACT_BOOLEAN_TRUE = 0x01, | |
54 | COMPACT_BOOLEAN_FALSE = 0x02, | |
55 | COMPACT_BYTE = 0x03, | |
56 | COMPACT_I16 = 0x04, | |
57 | COMPACT_I32 = 0x05, | |
58 | COMPACT_I64 = 0x06, | |
59 | COMPACT_DOUBLE = 0x07, | |
60 | COMPACT_BINARY = 0x08, | |
61 | COMPACT_LIST = 0x09, | |
62 | COMPACT_SET = 0x0A, | |
63 | COMPACT_MAP = 0x0B, | |
64 | COMPACT_STRUCT = 0x0C | |
65 | } | |
66 | ||
67 | TTypeToCompactType = {} | |
68 | TTypeToCompactType[TType.STOP] = TType.STOP | |
69 | TTypeToCompactType[TType.BOOL] = TCompactType.COMPACT_BOOLEAN_TRUE | |
70 | TTypeToCompactType[TType.BYTE] = TCompactType.COMPACT_BYTE | |
71 | TTypeToCompactType[TType.I16] = TCompactType.COMPACT_I16 | |
72 | TTypeToCompactType[TType.I32] = TCompactType.COMPACT_I32 | |
73 | TTypeToCompactType[TType.I64] = TCompactType.COMPACT_I64 | |
74 | TTypeToCompactType[TType.DOUBLE] = TCompactType.COMPACT_DOUBLE | |
75 | TTypeToCompactType[TType.STRING] = TCompactType.COMPACT_BINARY | |
76 | TTypeToCompactType[TType.LIST] = TCompactType.COMPACT_LIST | |
77 | TTypeToCompactType[TType.SET] = TCompactType.COMPACT_SET | |
78 | TTypeToCompactType[TType.MAP] = TCompactType.COMPACT_MAP | |
79 | TTypeToCompactType[TType.STRUCT] = TCompactType.COMPACT_STRUCT | |
80 | ||
81 | CompactTypeToTType = {} | |
82 | CompactTypeToTType[TType.STOP] = TType.STOP | |
83 | CompactTypeToTType[TCompactType.COMPACT_BOOLEAN_TRUE] = TType.BOOL | |
84 | CompactTypeToTType[TCompactType.COMPACT_BOOLEAN_FALSE] = TType.BOOL | |
85 | CompactTypeToTType[TCompactType.COMPACT_BYTE] = TType.BYTE | |
86 | CompactTypeToTType[TCompactType.COMPACT_I16] = TType.I16 | |
87 | CompactTypeToTType[TCompactType.COMPACT_I32] = TType.I32 | |
88 | CompactTypeToTType[TCompactType.COMPACT_I64] = TType.I64 | |
89 | CompactTypeToTType[TCompactType.COMPACT_DOUBLE] = TType.DOUBLE | |
90 | CompactTypeToTType[TCompactType.COMPACT_BINARY] = TType.STRING | |
91 | CompactTypeToTType[TCompactType.COMPACT_LIST] = TType.LIST | |
92 | CompactTypeToTType[TCompactType.COMPACT_SET] = TType.SET | |
93 | CompactTypeToTType[TCompactType.COMPACT_MAP] = TType.MAP | |
94 | CompactTypeToTType[TCompactType.COMPACT_STRUCT] = TType.STRUCT | |
95 | ||
96 | function TCompactProtocol:resetLastField() | |
97 | self.lastField = {} | |
98 | self.lastFieldId = 0 | |
99 | self.lastFieldIndex = 1 | |
100 | end | |
101 | ||
102 | function TCompactProtocol:packCompactType(ktype, vtype) | |
103 | return libluabitwise.bor(libluabitwise.shiftl(ktype, 4), vtype) | |
104 | end | |
105 | ||
106 | function TCompactProtocol:writeMessageBegin(name, ttype, seqid) | |
107 | self:writeByte(TCompactProtocol.COMPACT_PROTOCOL_ID) | |
108 | self:writeByte(libluabpack.packMesgType(TCompactProtocol.COMPACT_VERSION, | |
109 | TCompactProtocol.COMPACT_VERSION_MASK,ttype, | |
110 | TCompactProtocol.COMPACT_TYPE_SHIFT_AMOUNT, | |
111 | TCompactProtocol.COMPACT_TYPE_MASK)) | |
112 | self:writeVarint32(seqid) | |
113 | self:writeString(name) | |
114 | self:resetLastField() | |
115 | end | |
116 | ||
117 | function TCompactProtocol:writeMessageEnd() | |
118 | end | |
119 | ||
120 | function TCompactProtocol:writeStructBegin(name) | |
121 | self.lastFieldIndex = self.lastFieldIndex + 1 | |
122 | self.lastField[self.lastFieldIndex] = self.lastFieldId | |
123 | self.lastFieldId = 0 | |
124 | end | |
125 | ||
126 | function TCompactProtocol:writeStructEnd() | |
127 | self.lastFieldIndex = self.lastFieldIndex - 1 | |
128 | self.lastFieldId = self.lastField[self.lastFieldIndex] | |
129 | end | |
130 | ||
131 | function TCompactProtocol:writeFieldBegin(name, ttype, id) | |
132 | if ttype == TType.BOOL then | |
133 | self.booleanFieldName = name | |
134 | self.booleanFieldId = id | |
135 | self.booleanFieldPending = true | |
136 | else | |
137 | self:writeFieldBeginInternal(name, ttype, id, -1) | |
138 | end | |
139 | end | |
140 | ||
141 | function TCompactProtocol:writeFieldEnd() | |
142 | end | |
143 | ||
144 | function TCompactProtocol:writeFieldStop() | |
145 | self:writeByte(TType.STOP); | |
146 | end | |
147 | ||
148 | function TCompactProtocol:writeMapBegin(ktype, vtype, size) | |
149 | if size == 0 then | |
150 | self:writeByte(0) | |
151 | else | |
152 | self:writeVarint32(size) | |
153 | self:writeByte(self:packCompactType(TTypeToCompactType[ktype], TTypeToCompactType[vtype])) | |
154 | end | |
155 | end | |
156 | ||
157 | function TCompactProtocol:writeMapEnd() | |
158 | end | |
159 | ||
160 | function TCompactProtocol:writeListBegin(etype, size) | |
161 | self:writeCollectionBegin(etype, size) | |
162 | end | |
163 | ||
164 | function TCompactProtocol:writeListEnd() | |
165 | end | |
166 | ||
167 | function TCompactProtocol:writeSetBegin(etype, size) | |
168 | self:writeCollectionBegin(etype, size) | |
169 | end | |
170 | ||
171 | function TCompactProtocol:writeSetEnd() | |
172 | end | |
173 | ||
174 | function TCompactProtocol:writeBool(bool) | |
175 | local value = TCompactType.COMPACT_BOOLEAN_FALSE | |
176 | if bool then | |
177 | value = TCompactType.COMPACT_BOOLEAN_TRUE | |
178 | end | |
179 | print(value,self.booleanFieldPending,self.booleanFieldId) | |
180 | if self.booleanFieldPending then | |
181 | self:writeFieldBeginInternal(self.booleanFieldName, TType.BOOL, self.booleanFieldId, value) | |
182 | self.booleanFieldPending = false | |
183 | else | |
184 | self:writeByte(value) | |
185 | end | |
186 | end | |
187 | ||
188 | function TCompactProtocol:writeByte(byte) | |
189 | local buff = libluabpack.bpack('c', byte) | |
190 | self.trans:write(buff) | |
191 | end | |
192 | ||
193 | function TCompactProtocol:writeI16(i16) | |
194 | self:writeVarint32(libluabpack.i32ToZigzag(i16)) | |
195 | end | |
196 | ||
197 | function TCompactProtocol:writeI32(i32) | |
198 | self:writeVarint32(libluabpack.i32ToZigzag(i32)) | |
199 | end | |
200 | ||
201 | function TCompactProtocol:writeI64(i64) | |
202 | self:writeVarint64(libluabpack.i64ToZigzag(i64)) | |
203 | end | |
204 | ||
205 | function TCompactProtocol:writeDouble(dub) | |
206 | local buff = libluabpack.bpack('d', dub) | |
207 | self.trans:write(buff) | |
208 | end | |
209 | ||
210 | function TCompactProtocol:writeString(str) | |
211 | -- Should be utf-8 | |
212 | self:writeBinary(str) | |
213 | end | |
214 | ||
215 | function TCompactProtocol:writeBinary(str) | |
216 | -- Should be utf-8 | |
217 | self:writeVarint32(string.len(str)) | |
218 | self.trans:write(str) | |
219 | end | |
220 | ||
221 | function TCompactProtocol:writeFieldBeginInternal(name, ttype, id, typeOverride) | |
222 | if typeOverride == -1 then | |
223 | typeOverride = TTypeToCompactType[ttype] | |
224 | end | |
225 | local offset = id - self.lastFieldId | |
226 | if id > self.lastFieldId and offset <= 15 then | |
227 | self:writeByte(libluabitwise.bor(libluabitwise.shiftl(offset, 4), typeOverride)) | |
228 | else | |
229 | self:writeByte(typeOverride) | |
230 | self:writeI16(id) | |
231 | end | |
232 | self.lastFieldId = id | |
233 | end | |
234 | ||
235 | function TCompactProtocol:writeCollectionBegin(etype, size) | |
236 | if size <= 14 then | |
237 | self:writeByte(libluabitwise.bor(libluabitwise.shiftl(size, 4), TTypeToCompactType[etype])) | |
238 | else | |
239 | self:writeByte(libluabitwise.bor(0xf0, TTypeToCompactType[etype])) | |
240 | self:writeVarint32(size) | |
241 | end | |
242 | end | |
243 | ||
244 | function TCompactProtocol:writeVarint32(i32) | |
245 | -- Should be utf-8 | |
246 | local str = libluabpack.toVarint32(i32) | |
247 | self.trans:write(str) | |
248 | end | |
249 | ||
250 | function TCompactProtocol:writeVarint64(i64) | |
251 | -- Should be utf-8 | |
252 | local str = libluabpack.toVarint64(i64) | |
253 | self.trans:write(str) | |
254 | end | |
255 | ||
256 | function TCompactProtocol:readMessageBegin() | |
257 | local protocolId = self:readSignByte() | |
258 | if protocolId ~= self.COMPACT_PROTOCOL_ID then | |
259 | terror(TProtocolException:new{ | |
260 | message = "Expected protocol id " .. self.COMPACT_PROTOCOL_ID .. " but got " .. protocolId}) | |
261 | end | |
262 | local versionAndType = self:readSignByte() | |
263 | local version = libluabitwise.band(versionAndType, self.COMPACT_VERSION_MASK) | |
264 | local ttype = libluabitwise.band(libluabitwise.shiftr(versionAndType, | |
265 | self.COMPACT_TYPE_SHIFT_AMOUNT), self.COMPACT_TYPE_BITS) | |
266 | if version ~= self.COMPACT_VERSION then | |
267 | terror(TProtocolException:new{ | |
268 | message = "Expected version " .. self.COMPACT_VERSION .. " but got " .. version}) | |
269 | end | |
270 | local seqid = self:readVarint32() | |
271 | local name = self:readString() | |
272 | return name, ttype, seqid | |
273 | end | |
274 | ||
275 | function TCompactProtocol:readMessageEnd() | |
276 | end | |
277 | ||
278 | function TCompactProtocol:readStructBegin() | |
279 | self.lastField[self.lastFieldIndex] = self.lastFieldId | |
280 | self.lastFieldIndex = self.lastFieldIndex + 1 | |
281 | self.lastFieldId = 0 | |
282 | return nil | |
283 | end | |
284 | ||
285 | function TCompactProtocol:readStructEnd() | |
286 | self.lastFieldIndex = self.lastFieldIndex - 1 | |
287 | self.lastFieldId = self.lastField[self.lastFieldIndex] | |
288 | end | |
289 | ||
290 | function TCompactProtocol:readFieldBegin() | |
291 | local field_and_ttype = self:readSignByte() | |
292 | local ttype = self:getTType(field_and_ttype) | |
293 | if ttype == TType.STOP then | |
294 | return nil, ttype, 0 | |
295 | end | |
296 | -- mask off the 4 MSB of the type header. it could contain a field id delta. | |
297 | local modifier = libluabitwise.shiftr(libluabitwise.band(field_and_ttype, 0xf0), 4) | |
298 | local id = 0 | |
299 | if modifier == 0 then | |
300 | id = self:readI16() | |
301 | else | |
302 | id = self.lastFieldId + modifier | |
303 | end | |
304 | if ttype == TType.BOOL then | |
305 | boolValue = libluabitwise.band(field_and_ttype, 0x0f) == TCompactType.COMPACT_BOOLEAN_TRUE | |
306 | boolValueIsNotNull = true | |
307 | end | |
308 | self.lastFieldId = id | |
309 | return nil, ttype, id | |
310 | end | |
311 | ||
312 | function TCompactProtocol:readFieldEnd() | |
313 | end | |
314 | ||
315 | function TCompactProtocol:readMapBegin() | |
316 | local size = self:readVarint32() | |
317 | if size < 0 then | |
318 | return nil,nil,nil | |
319 | end | |
320 | local kvtype = self:readSignByte() | |
321 | local ktype = self:getTType(libluabitwise.shiftr(kvtype, 4)) | |
322 | local vtype = self:getTType(kvtype) | |
323 | return ktype, vtype, size | |
324 | end | |
325 | ||
326 | function TCompactProtocol:readMapEnd() | |
327 | end | |
328 | ||
329 | function TCompactProtocol:readListBegin() | |
330 | local size_and_type = self:readSignByte() | |
331 | local size = libluabitwise.band(libluabitwise.shiftr(size_and_type, 4), 0x0f) | |
332 | if size == 15 then | |
333 | size = self:readVarint32() | |
334 | end | |
335 | if size < 0 then | |
336 | return nil,nil | |
337 | end | |
338 | local etype = self:getTType(libluabitwise.band(size_and_type, 0x0f)) | |
339 | return etype, size | |
340 | end | |
341 | ||
342 | function TCompactProtocol:readListEnd() | |
343 | end | |
344 | ||
345 | function TCompactProtocol:readSetBegin() | |
346 | return self:readListBegin() | |
347 | end | |
348 | ||
349 | function TCompactProtocol:readSetEnd() | |
350 | end | |
351 | ||
352 | function TCompactProtocol:readBool() | |
353 | if boolValueIsNotNull then | |
354 | boolValueIsNotNull = true | |
355 | return boolValue | |
356 | end | |
357 | local val = self:readSignByte() | |
358 | if val == TCompactType.COMPACT_BOOLEAN_TRUE then | |
359 | return true | |
360 | end | |
361 | return false | |
362 | end | |
363 | ||
364 | function TCompactProtocol:readByte() | |
365 | local buff = self.trans:readAll(1) | |
366 | local val = libluabpack.bunpack('c', buff) | |
367 | return val | |
368 | end | |
369 | ||
370 | function TCompactProtocol:readSignByte() | |
371 | local buff = self.trans:readAll(1) | |
372 | local val = libluabpack.bunpack('C', buff) | |
373 | return val | |
374 | end | |
375 | ||
376 | function TCompactProtocol:readI16() | |
377 | return self:readI32() | |
378 | end | |
379 | ||
380 | function TCompactProtocol:readI32() | |
381 | local v = self:readVarint32() | |
382 | local value = libluabpack.zigzagToI32(v) | |
383 | return value | |
384 | end | |
385 | ||
386 | function TCompactProtocol:readI64() | |
387 | local value = self:readVarint64() | |
388 | return value | |
389 | end | |
390 | ||
391 | function TCompactProtocol:readDouble() | |
392 | local buff = self.trans:readAll(8) | |
393 | local val = libluabpack.bunpack('d', buff) | |
394 | return val | |
395 | end | |
396 | ||
397 | function TCompactProtocol:readString() | |
398 | return self:readBinary() | |
399 | end | |
400 | ||
401 | function TCompactProtocol:readBinary() | |
402 | local size = self:readVarint32() | |
403 | if size <= 0 then | |
404 | return "" | |
405 | end | |
406 | return self.trans:readAll(size) | |
407 | end | |
408 | ||
409 | function TCompactProtocol:readVarint32() | |
410 | local shiftl = 0 | |
411 | local result = 0 | |
412 | while true do | |
413 | b = self:readByte() | |
414 | result = libluabitwise.bor(result, | |
415 | libluabitwise.shiftl(libluabitwise.band(b, 0x7f), shiftl)) | |
416 | if libluabitwise.band(b, 0x80) ~= 0x80 then | |
417 | break | |
418 | end | |
419 | shiftl = shiftl + 7 | |
420 | end | |
421 | return result | |
422 | end | |
423 | ||
424 | function TCompactProtocol:readVarint64() | |
425 | local result = liblualongnumber.new | |
426 | local data = result(0) | |
427 | local shiftl = 0 | |
428 | while true do | |
429 | b = self:readByte() | |
430 | endFlag, data = libluabpack.fromVarint64(b, shiftl, data) | |
431 | shiftl = shiftl + 7 | |
432 | if endFlag == 0 then | |
433 | break | |
434 | end | |
435 | end | |
436 | return data | |
437 | end | |
438 | ||
439 | function TCompactProtocol:getTType(ctype) | |
440 | return CompactTypeToTType[libluabitwise.band(ctype, 0x0f)] | |
441 | end | |
442 | ||
443 | TCompactProtocolFactory = TProtocolFactory:new{ | |
444 | __type = 'TCompactProtocolFactory', | |
445 | } | |
446 | ||
447 | function TCompactProtocolFactory:getProtocol(trans) | |
448 | -- TODO Enforce that this must be a transport class (ie not a bool) | |
449 | if not trans then | |
450 | terror(TProtocolException:new{ | |
451 | message = 'Must supply a transport to ' .. ttype(self) | |
452 | }) | |
453 | end | |
454 | return TCompactProtocol:new{ | |
455 | trans = trans | |
456 | } | |
457 | end |