diff options
-rw-r--r-- | python/qpid/codec.py | 96 | ||||
-rw-r--r-- | python/qpid/spec.py | 7 | ||||
-rw-r--r-- | python/tests/codec.py | 7 |
3 files changed, 87 insertions, 23 deletions
diff --git a/python/qpid/codec.py b/python/qpid/codec.py index d0a95debb3..f6b0f980cb 100644 --- a/python/qpid/codec.py +++ b/python/qpid/codec.py @@ -34,6 +34,11 @@ from reference import ReferenceId class EOF(Exception): pass +TYPE_ALIASES = { + "long_string": "longstr", + "unsigned_int": "long" + } + class Codec: """ @@ -51,6 +56,40 @@ class Codec: self.incoming_bits = [] self.outgoing_bits = [] + self.types = {} + self.codes = {} + self.encodings = { + basestring: "longstr", + int: "long", + long: "long", + None.__class__:"void", + list: "sequence", + tuple: "sequence", + dict: "table" + } + + if False: + for constant in self.spec.constants: + if constant.klass == "field-table-type": + type = constant.name.replace("field_table_", "") + self.typecode(constant.id, TYPE_ALIASES.get(type, type)) + + if not self.types: + self.typecode(ord('S'), "longstr") + self.typecode(ord('I'), "long") + + def typecode(self, code, type): + self.types[code] = type + self.codes[type] = code + + def resolve(self, klass): + if self.encodings.has_key(klass): + return self.encodings[klass] + for base in klass.__bases__: + result = self.resolve(base) + if result != None: + return result + def read(self, n): """ reads in 'n' bytes from the stream. Can raise EOF exception @@ -265,15 +304,14 @@ class Codec: codec = Codec(enc, self.spec) if tbl: for key, value in tbl.items(): - if len(key) > 128: + if self.spec.major == 8 and self.spec.minor == 0 and len(key) > 128: raise ValueError("field table key too long: '%s'" % key) + type = self.resolve(value.__class__) + if type == None: + raise ValueError("no encoding for: " + value.__class__) codec.encode_shortstr(key) - if isinstance(value, basestring): - codec.write("S") - codec.encode_longstr(value) - else: - codec.write("I") - codec.encode_long(value) + codec.encode_octet(self.codes[type]) + codec.encode(type, value) s = enc.getvalue() self.encode_long(len(s)) self.write(s) @@ -287,13 +325,21 @@ class Codec: result = {} while self.nread - start < size: key = self.decode_shortstr() - type = self.read(1) - if type == "S": - value = self.decode_longstr() - elif type == "I": - value = self.decode_long() + code = self.decode_octet() + if self.types.has_key(code): + value = self.decode(self.types[code]) else: - raise ValueError(repr(type)) + w = width(code) + if fixed(code): + value = self.read(w) + elif w == 1: + value = self.decode_shortstr() + elif w == 2: + value = self.dec_str("!H") + elif w == 4: + value = self.decode_longstr() + else: + raise ValueError("illegal width: " + w) result[key] = value return result @@ -390,3 +436,27 @@ class Codec: codec = Codec(StringIO(self.decode_longstr()), self.spec) type = self.spec.structs[codec.decode_short()] return codec.decode_struct(type) + +def fixed(code): + return (code >> 6) != 2 + +def width(code): + # decimal + if code >= 192: + decsel = (code >> 4) & 3 + if decsel == 0: + return 5 + elif decsel == 1: + return 9 + elif decsel == 3: + return 0 + else: + raise ValueError(code) + # variable width + elif code < 192 and code >= 128: + lenlen = (self.code >> 4) & 3 + if lenlen == 3: raise ValueError(code) + return 2 ** lenlen + # fixed width + else: + return (self.code >> 4) & 7 diff --git a/python/qpid/spec.py b/python/qpid/spec.py index 3cb5f0ca25..2542ccc3e1 100644 --- a/python/qpid/spec.py +++ b/python/qpid/spec.py @@ -348,9 +348,10 @@ def load(specfile, *errata): # constants for nd in root.query["constant"]: val = nd["@value"] - if val.startswith("0x"): continue - const = Constant(spec, pythonize(nd["@name"]), int(val), - nd["@class"], get_docs(nd)) + if val.startswith("0x"): val = int(val, 16) + else: val = int(val) + const = Constant(spec, pythonize(nd["@name"]), val, nd["@class"], + get_docs(nd)) try: spec.constants.add(const) except ValueError, e: diff --git a/python/tests/codec.py b/python/tests/codec.py index fbaf05fc20..e23c3deca1 100644 --- a/python/tests/codec.py +++ b/python/tests/codec.py @@ -442,13 +442,6 @@ class FieldTableTestCase(BaseDataTypes): """ self.failUnlessEqual(self.callFunc('encode_table', {'$key1':'value1'}), '\x00\x00\x00\x11\x05$key1S\x00\x00\x00\x06value1', 'valid name value pair encoding FAILED...') - # ---------------------------------------------------- - def test_field_table_invalid_field_name_length(self): - """ - field names can have a maximum length of 128 chars - """ - self.failUnlessRaises(Exception, self.codec.encode_table, {'x'*129:'value1'}) - # --------------------------------------------------- def test_field_table_multiple_name_value_pair(self): """ |