[ create a new paste ] login | about

Link: http://codepad.org/xct0E5ac    [ raw code | output | fork | 3 comments ]

Python, pasted on Mar 20:
def parse_payload(data):
    assert data, "Invalid data to parse, it's empty."
    length, extra = data.split(':', 1)
    length = int(length)

    payload, extra = extra[:length], extra[length:]
    assert extra, "No payload type: %r, %r" % (payload, extra)
    payload_type, remain = extra[0], extra[1:]

    assert len(payload) == length, "Data is wrong length %d vs %d" % (length, len(payload))
    return payload, payload_type, remain

def parse_list(data):
    if len(data) == 0: return []

    result = []
    value, extra = parse_tnetstring(data)
    result.append(value)

    while extra:
        value, extra = parse_tnetstring(extra)
        result.append(value)

    return result

def parse_pair(data):
    key, extra = parse_tnetstring(data)
    assert extra, "Unbalanced dictionary store."
    value, extra = parse_tnetstring(extra)
    assert value, "Got an invalid value, null not allowed."

    return key, value, extra

def parse_dict(data):
    if len(data) == 0: return {}

    key, value, extra = parse_pair(data)
    result = {key: value}

    while extra:
        key, value, extra = parse_pair(extra)
        result[key] = value
  
    return result
    
def parse_tnetstring(data):
    payload, payload_type, remain = parse_payload(data)

    if payload_type == '#':
        value = int(payload)
    elif payload_type == '"':
        value = payload
    elif payload_type == '}':
        value = parse_dict(payload)
    elif payload_type == ']':
        value = parse_list(payload)
    else:
        assert False, "Invalid payload type: %r" % payload_type

    return value, remain

TESTS = {
    '0:}': {},
    '0:]': [],
    '34:5:hello"22:11:12345678901#4:this"]}': {'hello': [12345678901, 'this']},
    '5:12345#': 12345,
    '12:this is cool"': "this is cool",
    '0:"': "",
    '24:5:12345#5:67890#5:xxxxx"]': [12345, 67890, 'xxxxx'],
}

for data, expect in TESTS.items():
    payload, remain = parse_tnetstring(data)
    assert not remain, "Had trailing junk: %r" % remain
    assert payload != None, "Didn't get a payload."

    print "EXPECT", repr(expect), "GOT", repr(payload)


Output:
1
2
3
4
5
6
7
EXPECT {} GOT {}
EXPECT [] GOT []
EXPECT {'hello': [12345678901L, 'this']} GOT {'hello': [12345678901L, 'this']}
EXPECT [12345, 67890, 'xxxxx'] GOT [12345, 67890, 'xxxxx']
EXPECT 'this is cool' GOT 'this is cool'
EXPECT 12345 GOT 12345
EXPECT '' GOT ''


Create a new paste based on this one


Comments:
posted by seanohalpin on Mar 22
You could shorten the data even more (though lose some readability) by using the type characters as delimiters, e.g.

import re
def parse_payload(data):
assert data, "Invalid data to parse, it's empty."
length, payload_type, extra = re.split('([#}\]"])', data, 1)
length = int(length)
payload, extra = extra[:length], extra[length:]
return payload, payload_type, extra

and

TESTS = {
'0}': {},
'0]': [],
'5"hello': 'hello',
'30}5"hello20]11#123456789014"this': {'hello': [12345678901, 'this']},
'5#12345': 12345,
'12"this is cool': "this is cool",
'0"': "",
'21]5#123455#678905"xxxxx': [12345, 67890, 'xxxxx'],
}

Regards,
Sean


reply
posted by michaelnugent on Mar 31

I felt this could be a fit fragile outside of environments with guaranteed and in order delivery of packets so I build a very simple checksum to give it an added degree of safety.

http://codepad.org/eJWYNqvl


reply
posted by michaelnugent on Mar 31
codepad seems to have added some html to my link to their site :)

http://codepad.org/eJWYNqvl
reply