增加汇多协议封装
diff --git a/supwisdom/protocol/amassprotocol.py b/supwisdom/protocol/amassprotocol.py
new file mode 100644
index 0000000..746abd1
--- /dev/null
+++ b/supwisdom/protocol/amassprotocol.py
@@ -0,0 +1,375 @@
+# -*- coding: utf-8

+""" »ã¶àЭÒé·â×°

+"""

+import codecs

+import struct

+

+IFT_NULL = 0

+IFT_ULONG = 1

+IFT_BYTE = 2

+IFT_USHORT = 3

+IFT_DATETIME = 4

+IFT_BUFFER = 5

+IFT_STRING = 6

+IFT_LONG = 7

+

+# (0,0,1,IFT_BYTE,0,"msgtype","ÏûÏ¢Âë"),

+

+FLD_NO_IDX = 0

+FLD_LENGTH_IDX = 2

+FLD_TYPE_IDX = 3

+FLD_FLAG_IDX = 4

+FLD_NAME_IDX = 5

+FLD_DESC_IDX = 6

+

+HDFieldsDef = [

+(1, 0, 0, IFT_NULL, 0, "extend", u"À©Õ¹Óò·ñ"),

+(2, 0, 4, IFT_ULONG, 0, "terminalsn", u" ÖÕ¶ËÐòÁкÅ"),

+(3, 0, 2, IFT_USHORT, 0, "address", u"CANµØÖ·"),

+(4, 0, 4, IFT_ULONG, 0, "cardnumber", u"¿¨ºÅ"),

+(5, 0, 1, IFT_BYTE, 0, "indexofew", u" Ç®°üË÷Òý"),

+(6, 0, 2, IFT_USHORT, 0, "traceofew", u" Ç®°üÁ÷Ë®ºÅ"),

+(7, 0, 4, IFT_LONG, 0, "amount", u" ½»Ò×½ð¶î"),

+(8, 0, 4, IFT_LONG, 0, "additionalamount1", u"¸½¼Ó½ð¶î"),

+(9, 0, 4, IFT_ULONG, 0, "traceofpos", u"POSÁ÷Ë®ºÅ"),

+(10, 0, 4, IFT_ULONG, 0, "orgtranstrace", u"Ô­½»Ò×Á÷Ë®ºÅ"),

+(11, 0, 7, IFT_DATETIME, 0, "datetime", u"½»Ò×ÈÕÆÚºÍʱ¼ä"),

+(12, 0, 1, IFT_BYTE, 0, "responsecode", u"ÏìÓ¦Âë"),

+(13, 0, 2, IFT_USHORT, 0, "terminalid", u"Öն˺Å"),

+(14, 0, 2, IFT_USHORT, 0, "terminaltype", u"ÖÕ¶ËÀàÐÍ"),

+(15, 0, 2, IFT_USHORT, 0, "merchantid", u"ÉÌ»§(Íøµã)ºÅ"),

+(16, 0, 4, IFT_ULONG, 0, "operatorid", u"²Ù×÷Ô±ºÅ"),

+(17, 0, 8, IFT_BUFFER, 0, "pin", u"¸öÈËʶ±ðÂëPIN"),

+(18, 0, 4, IFT_ULONG, 0, "veroflist", u"ºÚÃûµ¥°æ±¾"),

+(19, 0, 4, IFT_ULONG, 0, "managefee", u"½»Ò×Åú´ÎºÅ(Ôݲ»ÓÃ)"),

+(20, 0, 360, IFT_BUFFER, 2, "additionaldata1", u"¸½¼ÓÐÅÏ¢1"),

+(21, 0, 528, IFT_BUFFER, 2, "additionaldata2", u"¸½¼ÓÐÅÏ¢2"),

+(22, 0, 528, IFT_STRING, 2, "additionaldata3", u"¸½¼ÓÐÅÏ¢3"),

+(23, 0, 528, IFT_STRING, 2, "additionaldata4", u"¸½¼ÓÐÅÏ¢4"),

+(24, 0, 2, IFT_USHORT, 0, "mac", u"ÏûÏ¢ÈÏÖ¤Âë")]

+

+

+class HDPack:

+    ''' »ã¶à 8583 ЭÒé°ü '''

+    def __init__(self):

+        self.msg_type = 0

+        self.value = {}

+        self.field_idx = {}

+        self.field_name = {}

+        self.msgtype = 0

+        self.load_config()

+

+    def __eq__(self, other):

+        if not isinstance(other, HDPack):

+            return False

+        return self.compare(other)

+

+    def __ne__(self, other):

+        if not isinstance(other, HDPack):

+            return True

+        return not self.compare(other)

+

+    def compare(self, other):

+        if self.msgtype != other.msgtype:

+            return False

+        for k, v in self.value.items():

+            if k not in other.value:

+                print "field [%s] not equal" % k

+                return False

+            if v != other.get(k):

+                print "field [%s] value not equal [%s,%s]" % (k, v, other.get(k))

+                return False

+        return True

+

+    def load_config(self):

+        for field in HDFieldsDef:

+            index, t, len, type, flag, name, desc = field

+            self.field_idx[index] = field

+            self.field_name[name] = field

+        #print self.field_name

+

+    def get_field_def(self, index):

+        field_def = None

+        if isinstance(index, int):

+            if index not in self.field_idx:

+                raise ValueError("field index %d not exists" % index)

+            field_def = self.field_idx[index]

+        elif isinstance(index, str):

+            if index not in self.field_name:

+                raise ValueError("field index %s not exists" % index)

+            field_def = self.field_name[index]

+        else:

+            raise ValueError("field index type not support")

+        return field_def

+

+    def set(self, index, value):

+        field_def = self.get_field_def(index)

+        t = field_def[FLD_TYPE_IDX]

+        n = field_def[FLD_NAME_IDX]

+        l = field_def[FLD_LENGTH_IDX]

+        f = field_def[FLD_FLAG_IDX]

+        if t == IFT_USHORT or t == IFT_ULONG or t == IFT_NULL or t == IFT_BYTE or t == IFT_LONG:

+            if isinstance(value, int):

+                b = value

+            elif isinstance(value, str):

+                if value.startswith('0x'):

+                    b = int(value, 16)

+                else:

+                    b = int(value)

+            else:

+                raise ValueError("field %s value type not integer" % n)

+        elif t == IFT_DATETIME:

+            if len(value) != 12 and len(value) != 14:

+                raise ValueError("field %s length must be 12 or 14" % n)

+            if len(value) == 14:

+                value = value[2:]

+            b = value + "00"

+        else:

+            if not isinstance(value, str):

+                raise ValueError("field %s value type not string" % n)

+            if t == IFT_DATETIME:

+                l *= 2

+            elif value.startswith('0x'):

+                l *= 2

+                l += 2

+            if f != 2 and len(value) != l:

+                raise ValueError("field %s value data length not equal %d<>%d " %

+                    (n, len(value), l))

+            elif len(value) > l:

+                raise ValueError("field %s value data length exceed %d " % (n, l))

+            b = value

+        self.value[n] = b

+

+    def get(self, index):

+        field_def = self.get_field_def(index)

+        #t = field_def[3]

+        n = field_def[5]

+        if n in self.value:

+            return self.value[n]

+        raise ValueError("Field %s not specified" % n)

+

+    def encode_bitmap(self, bitmap):

+        buffer = []

+        offset = 0

+        #print "bit len[%d]" % len(bitmap)

+        while offset < len(bitmap):

+            bit = 0

+            for i in range(8):

+                t = ord(bitmap[offset + i]) - 0x30

+                if t == 0: continue

+                bit |= (1 << (7 - i % 8))

+            buffer.append(chr(bit & 0xFF))

+            offset += 8

+        return "".join(buffer)

+

+    def pack(self, workkey=None):

+        buffer = []

+        bitmap = ['0' for i in range(24)]

+        for field in HDFieldsDef:

+            index, x, len, t, flag, name, desc = field

+            if name not in self.value:

+                continue

+            if t == IFT_USHORT or t == IFT_ULONG or t == IFT_NULL or t == IFT_BYTE or t == IFT_LONG:

+                buffer.append(self.int_2_buffer(self.value[name], t, len))

+            else:

+                buffer.append(self.string_2_buffer(self.value[name], t, len, flag))

+            bitmap[index - 1] = '1'

+        #print bitmap

+        bitmap_buffer = self.encode_bitmap(bitmap)

+        full_data = chr(self.msgtype & 0xFF) + bitmap_buffer + "".join(buffer)

+        header = self.data_header(full_data)

+        #print "h[%s]d[%s]" % (codecs.encode(header,'hex'),codecs.encode(full_data,'hex'))

+        return header + full_data

+

+    def data_header(self, buffer):

+        if len(buffer) > 0xFFFF:

+            raise ValueError("Buffer max length exceed %d", len(buffer))

+        header = struct.pack('<H', len(buffer))

+        return header

+

+    def int_2_buffer(self, value, type, length):

+        buffer = ''

+        if type == IFT_BYTE:

+            buffer = chr(value % 0x100)

+        elif type == IFT_NULL:

+            return buffer

+        elif type == IFT_USHORT:

+            v = value % 0x10000

+            buffer = struct.pack('<H', v)

+        elif type == IFT_ULONG:

+            buffer = struct.pack('<I', value)

+        elif type == IFT_LONG:

+            buffer = struct.pack('<i', value)

+        else:

+            raise ValueError('Input Error')

+        return buffer

+

+    def encode_bcd(self, value):

+        if len(value) % 2 != 0:

+            raise ValueError("value length must div 2")

+        i = 0

+        #print "value [%s]" % value

+        buffer = []

+        while i < len(value):

+            t1 = (ord(value[i]) - 0x30) & 0xFF

+            t2 = (ord(value[i + 1]) - 0x30) & 0xFF

+            #print "t1[%d]t2[%d]" % (t1,t2)

+            t = ((t1 << 4) | t2) & 0xFF

+            #print "t1[%d]t2[%d]t[%d]" % (t1,t2,t)

+            buffer.append(chr(t))

+            i += 2

+        #print "bcd value[%s]" % codecs.encode(buffer,'hex')

+        return "".join(buffer)

+

+    def decode_bcd(self, value):

+        buffer = []

+        #print "bcd [%s]" % codecs.encode(value,'hex')

+        for c in value:

+            t = ord(c) & 0xFF

+            t1 = (t >> 4) & 0x0F

+            t2 = t & 0x0F

+            #print "t[%02x]t1[%d]t2[%d]" % (t,t1,t2)

+            buffer.append(chr(t1 + 0x30) + chr(t2 + 0x30))

+        #print "bcd value[%s]" % buffer

+        return "".join(buffer)

+

+    def string_2_buffer(self, value, type, length, flag):

+        buffer = ''

+        if type == IFT_STRING or type == IFT_BUFFER:

+            if value.startswith('0x'):

+                buffer = codecs.decode(value[2:], 'hex')

+            else:

+                buffer = value

+        elif type == IFT_DATETIME:

+            buffer = ''

+            i = 0

+            while i < len(value):

+                t = int(value[i:i + 2])

+                buffer += chr(t & 0xFF)

+                i += 2

+        else:

+            raise ValueError('Input Error')

+        if flag == 2:

+            header = struct.pack('<H', len(buffer) % 0x10000)

+            return header + buffer

+        else:

+            #if type == IFT_BUFFER:

+            #    if len(buffer) % 2 <> 0 or len(buffer)/2 <> length:

+            #        raise ValueError("Value length not matched [%s]" % value)

+            #    buffer = codecs.decode(buffer,'hex')

+            if len(buffer) != length:

+                padlen = length - len(buffer)

+                if padlen < 0:

+                    raise ValueError("Value length not matched [%s]" % value)

+                pad = chr(0) * padlen

+                buffer = pad + buffer

+            return buffer

+

+    def decode_bitmap(self, bitmap):

+        if len(bitmap) != 3:

+            raise ValueError("bitmap length error")

+        #print "bitmap[%s]" % codecs.encode(bitmap,'hex')

+        buffer = []

+        for t in bitmap:

+            v = ord(t) & 0xFF

+            for i in range(8):

+                x = (v & (1 << (7 - i)))

+                if x > 0:

+                    buffer.append('1')

+                else:

+                    buffer.append('0')

+        return buffer

+

+    def unpack(self, data):

+        self.value = {}

+        #print "data[%s]" % codecs.encode(data,'hex')

+        data_len = struct.unpack('<H', data[:2])[0]

+        if len(data) != data_len + 2:

+            print "input[%d] extually[%d]" % (data_len, len(data))

+            return False

+        offset = 2

+        self.msgtype = ord(data[offset]) & 0xFF

+        offset += 1

+        bitmap = self.decode_bitmap(data[offset:offset + 3])

+        offset += 3

+        #print bitmap

+        for i in range(len(bitmap)):

+            if bitmap[i] == '0': continue

+            findex = i + 1

+            field = self.get_field_def(findex)

+            ftype = field[FLD_TYPE_IDX]

+            flen = field[FLD_LENGTH_IDX]

+            fflag = field[FLD_FLAG_IDX]

+            #fname = field[FLD_NAME_IDX]

+            #print "parse field[%s] [%d]off[%d][%s]" % (fname,fflag,offset,codecs.encode(data[offset:offset+2],'hex'))

+            # ±ä³¤Êý¾Ý

+            if fflag == 2:

+                #print "len [%s]" % codecs.encode(data[offset:offset+2],'hex')

+                endpos = self.buffer_2_int(data[offset:offset + 2], IFT_USHORT)

+                offset += 2

+                endpos += offset

+            else:

+                endpos = offset + flen

+            if ftype == IFT_USHORT or ftype == IFT_ULONG or ftype == IFT_NULL or ftype == IFT_BYTE or ftype == IFT_LONG:

+                value = self.buffer_2_int(data[offset:endpos], ftype)

+            else:

+                #temp = self.buffer_2_string(data[offset:endpos],ftype)

+                #if fflag != 2 and ftype == IFT_STRING:

+                #    for i in temp:

+                #        print "char [%02x]" % ord(i)

+                #        if ord(i) > 0:

+                #            value += i

+                #else:

+                #    value = temp

+                value = self.buffer_2_string(data[offset:endpos], ftype)

+                if fflag != 2 and ftype == IFT_BUFFER:

+                    value = '0x' + codecs.encode(value, 'hex')

+            self.set(findex, value)

+            #print "parse field[%s] OK =====" % fname

+            offset = endpos

+        #print self.value

+        return True

+

+    def buffer_2_int(self, data, type):

+        if type == IFT_BYTE:

+            return ord(data)

+        elif type == IFT_USHORT:

+            return struct.unpack('<H', data)[0]

+        elif type == IFT_ULONG:

+            return struct.unpack('<I', data)[0]

+        elif type == IFT_LONG:

+            return struct.unpack('<i', data)[0]

+        elif type == IFT_NULL:

+            return None

+        else:

+            raise ValueError("input data type error")

+

+    def buffer_2_string(self, data, type):

+        if type == IFT_STRING:

+            return data

+        elif type == IFT_BUFFER:

+            return data

+        elif type == IFT_DATETIME:

+            return self.decode_bcd(data)

+        else:

+            raise ValueError("input data type error")

+

+    def get_2byte_int(self, data):

+        return struct.unpack(">H", data)[0]

+

+    def get_3byte_int(self, data):

+        temp = data + chr(0)

+        return struct.unpack("<I", temp)[0]

+

+    def get_4byte_int(self, data):

+        return struct.unpack("<I", data)[0]

+

+    def set_2byte_int(self, data):

+        return struct.pack('<H', data)

+

+    def set_3byte_int(self, data):

+        temp = struct.pack('<H', data)

+        return temp[:-1]

+

+    def set_4byte_int(self, data):

+        return struct.pack('<I', data)