blob: 389b6078531222179083233dac356a2ca8c7e1e6 [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
import struct
FIRST_SEG = 0x08
LAST_SEG = 0x04
FIRST_FRM = 0x02
LAST_FRM = 0x01
class Frame:
HEADER = "!2BHxBH4x"
HEADER_SIZE = struct.calcsize(HEADER)
MAX_PAYLOAD = 65535 - struct.calcsize(HEADER)
def __init__(self, flags, type, track, channel, payload):
if len(payload) > Frame.MAX_PAYLOAD:
raise ValueError("max payload size exceeded: %s" % len(payload))
self.flags = flags
self.type = type
self.track = track
self.channel = channel
self.payload = payload
def isFirstSegment(self):
return bool(FIRST_SEG & self.flags)
def isLastSegment(self):
return bool(LAST_SEG & self.flags)
def isFirstFrame(self):
return bool(FIRST_FRM & self.flags)
def isLastFrame(self):
return bool(LAST_FRM & self.flags)
def __repr__(self):
return "%s%s%s%s %s %s %s %r" % (int(self.isFirstSegment()),
int(self.isLastSegment()),
int(self.isFirstFrame()),
int(self.isLastFrame()),
self.type,
self.track,
self.channel,
self.payload)
class Segment:
def __init__(self, first, last, type, track, channel, payload):
self.id = None
self.offset = None
self.first = first
self.last = last
self.type = type
self.track = track
self.channel = channel
self.payload = payload
def __repr__(self):
return "%s%s %s %s %s %r" % (int(self.first), int(self.last), self.type,
self.track, self.channel, self.payload)
class FrameDecoder:
def __init__(self):
self.input = ""
self.output = []
self.parse = self.__frame_header
def write(self, bytes):
self.input += bytes
while True:
next = self.parse()
if next is None:
break
else:
self.parse = next
def __consume(self, n):
result = self.input[:n]
self.input = self.input[n:]
return result
def __frame_header(self):
if len(self.input) >= Frame.HEADER_SIZE:
st = self.__consume(Frame.HEADER_SIZE)
self.flags, self.type, self.size, self.track, self.channel = \
struct.unpack(Frame.HEADER, st)
return self.__frame_body
def __frame_body(self):
size = self.size - Frame.HEADER_SIZE
if len(self.input) >= size:
payload = self.__consume(size)
frame = Frame(self.flags, self.type, self.track, self.channel, payload)
self.output.append(frame)
return self.__frame_header
def read(self):
result = self.output
self.output = []
return result
class FrameEncoder:
def __init__(self):
self.output = ""
def write(self, *frames):
for frame in frames:
size = len(frame.payload) + Frame.HEADER_SIZE
track = frame.track & 0x0F
self.output += struct.pack(Frame.HEADER, frame.flags, frame.type, size,
track, frame.channel)
self.output += frame.payload
def read(self):
result = self.output
self.output = ""
return result
class SegmentDecoder:
def __init__(self):
self.fragments = {}
self.segments = []
def write(self, *frames):
for frm in frames:
key = (frm.channel, frm.track)
seg = self.fragments.get(key)
if seg == None:
seg = Segment(frm.isFirstSegment(), frm.isLastSegment(),
frm.type, frm.track, frm.channel, "")
self.fragments[key] = seg
seg.payload += frm.payload
if frm.isLastFrame():
self.fragments.pop(key)
self.segments.append(seg)
def read(self):
result = self.segments
self.segments = []
return result
class SegmentEncoder:
def __init__(self, max_payload=Frame.MAX_PAYLOAD):
self.max_payload = max_payload
self.frames = []
def write(self, *segments):
for seg in segments:
remaining = seg.payload
first = True
while first or remaining:
payload = remaining[:self.max_payload]
remaining = remaining[self.max_payload:]
flags = 0
if first:
flags |= FIRST_FRM
first = False
if not remaining:
flags |= LAST_FRM
if seg.first:
flags |= FIRST_SEG
if seg.last:
flags |= LAST_SEG
frm = Frame(flags, seg.type, seg.track, seg.channel, payload)
self.frames.append(frm)
def read(self):
result = self.frames
self.frames = []
return result
from ops import COMMANDS, CONTROLS, COMPOUND, Header, segment_type, track
from codec010 import StringCodec
class OpEncoder:
def __init__(self):
self.segments = []
def write(self, *ops):
for op in ops:
if COMMANDS.has_key(op.NAME):
seg_type = segment_type.command
seg_track = track.command
enc = self.encode_command(op)
elif CONTROLS.has_key(op.NAME):
seg_type = segment_type.control
seg_track = track.control
enc = self.encode_compound(op)
else:
raise ValueError(op)
seg = Segment(True, False, seg_type, seg_track, op.channel, enc)
self.segments.append(seg)
if hasattr(op, "headers") and op.headers is not None:
hdrs = ""
for h in op.headers:
hdrs += self.encode_compound(h)
seg = Segment(False, False, segment_type.header, seg_track, op.channel,
hdrs)
self.segments.append(seg)
if hasattr(op, "payload") and op.payload is not None:
self.segments.append(Segment(False, False, segment_type.body, seg_track,
op.channel, op.payload))
self.segments[-1].last = True
def encode_command(self, cmd):
sc = StringCodec()
sc.write_uint16(cmd.CODE)
sc.write_compound(Header(sync=cmd.sync))
sc.write_fields(cmd)
return sc.encoded
def encode_compound(self, op):
sc = StringCodec()
sc.write_compound(op)
return sc.encoded
def read(self):
result = self.segments
self.segments = []
return result
class OpDecoder:
def __init__(self):
self.current_op = {}
self.ops = []
def write(self, *segments):
for seg in segments:
op = self.current_op.get(seg.track)
if seg.first:
if seg.type == segment_type.command:
op = self.decode_command(seg.payload)
elif seg.type == segment_type.control:
op = self.decode_control(seg.payload)
else:
raise ValueError(seg)
op.channel = seg.channel
elif seg.type == segment_type.header:
if op.headers is None:
op.headers = []
op.headers.extend(self.decode_headers(seg.payload))
elif seg.type == segment_type.body:
if op.payload is None:
op.payload = seg.payload
else:
op.payload += seg.payload
if seg.last:
self.ops.append(op)
if seg.track in self.current_op:
del self.current_op[seg.track]
else:
self.current_op[seg.track] = op
def decode_command(self, encoded):
sc = StringCodec(encoded)
code = sc.read_uint16()
cls = COMMANDS[code]
hdr = sc.read_compound(Header)
cmd = cls()
sc.read_fields(cmd)
cmd.sync = hdr.sync
return cmd
def decode_control(self, encoded):
sc = StringCodec(encoded)
code = sc.read_uint16()
cls = CONTROLS[code]
ctl = cls()
sc.read_fields(ctl)
return ctl
def decode_headers(self, encoded):
sc = StringCodec(encoded)
result = []
while sc.encoded:
result.append(sc.read_struct32())
return result
def read(self):
result = self.ops
self.ops = []
return result