struct.py :  » Ajax » pyjamas » src » pyjs » src » pyjs » lib » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Ajax » pyjamas 
pyjamas » src » pyjs » src » pyjs » lib » struct.py
# struct.py from the pypy project

# Modified for missing string multiplication
# Modified for missing list addition ([1] + [2])

"""Functions to convert between Python values and C structs.
Python strings are used to hold the data representing the C struct
and also as format strings to describe the layout of data in the C struct.

The optional first format char indicates byte order, size and alignment:
 @: native order, size & alignment (default)
 =: native order, std. size & alignment
 <: little-endian, std. size & alignment
 >: big-endian, std. size & alignment
 !: same as >

The remaining chars indicate types of args and must match exactly;
these can be preceded by a decimal repeat count:
   x: pad byte (no data);
   c:char;
   b:signed byte;
   B:unsigned byte;
   h:short;
   H:unsigned short;
   i:int;
   I:unsigned int;
   l:long;
   L:unsigned long;
   f:float;
   d:double.
Special cases (preceding decimal count indicates length):
   s:string (array of char); p: pascal string (with count byte).
Special case (only available in native format):
   P:an integer type that is wide enough to hold a pointer.
Special case (not in native mode unless 'long long' in platform C):
   q:long long;
   Q:unsigned long long
Whitespace between formats is ignored.

The variable struct.error is an exception raised on errors."""

import math, sys

# TODO: XXX Find a way to get information on native sizes and alignments
class StructError(Exception):
    pass
error = StructError
def unpack_int(data,index,size,le):
    bytes = [ord(b) for b in data[index:index+size]]
    if le == 'little':
        bytes.reverse()
    number = 0L
    for b in bytes:
        number = number << 8 | b
    return int(number)

def unpack_signed_int(data,index,size,le):
    number = unpack_int(data,index,size,le)
    max = 2**(size*8)
    if number > 2**(size*8 - 1) - 1:
        number = int(-1*(max - number))
    return number

def unpack_float(data,index,size,le):
    bytes = [ord(b) for b in data[index:index+size]]
    if len(bytes) != size:
        raise StructError,"Not enough data to unpack"
    if max(bytes) == 0:
        return 0.0
    if le == 'big':
        bytes.reverse()
    if size == 4:
        bias = 127
        exp = 8
        prec = 23
    else:
        bias = 1023
        exp = 11
        prec = 52
    mantissa = long(bytes[size-2] & (2**(15-exp)-1))
    #for b in bytes[size-3::-1]:
    #    mantissa = mantissa << 8 | b
    revbytes = bytes
    revbytes.reverse()
    for b in revbytes[3:]:
        mantissa = mantissa << 8 | b
    mantissa = 1 + (1.0*mantissa)/(2**(prec))
    mantissa /= 2
    e = (bytes[-1] & 0x7f) << (exp - 7)
    e += (bytes[size-2] >> (15 - exp)) & (2**(exp - 7) -1)
    e -= bias
    e += 1
    sign = bytes[-1] & 0x80
    number = math.ldexp(mantissa,e)
    if sign : number *= -1
    return number

def unpack_char(data,index,size,le):
    return data[index:index+size]

def pack_int(number,size,le):
    x=number
    res=[]
    for i in range(size):
        res.append(chr(x&0xff))
        x >>= 8
    if le == 'big':
        res.reverse()
    return ''.join(res)

def pack_signed_int(number,size,le):
    if not isinstance(number, (int,long)):
        raise StructError,"argument for i,I,l,L,q,Q,h,H must be integer"
    if  number > 2**(8*size-1)-1 or number < -1*2**(8*size-1):
        raise OverflowError,"Number:%i too large to convert" % number
    return pack_int(number,size,le)

def pack_unsigned_int(number,size,le):
    if not isinstance(number, (int,long)):
        raise StructError,"argument for i,I,l,L,q,Q,h,H must be integer"
    if number < 0:
        raise TypeError,"can't convert negative long to unsigned"
    if number > 2**(8*size)-1:
        raise OverflowError,"Number:%i too large to convert" % number
    return pack_int(number,size,le)

def pack_char(char,size,le):
    return str(char)

def sane_float(man,e):
    # TODO: XXX Implement checks for floats
    return True

def pack_float(number, size, le):

    if number < 0:
        sign = 1
        number *= -1
    elif number == 0.0:
        #return "\x00" * size
        return "".ljust(size, "\x00")
    else:
        sign = 0
    if size == 4:
        bias = 127
        exp = 8
        prec = 23
    else:
        bias = 1023
        exp = 11
        prec = 52

    man, e = math.frexp(number)
    if 0.5 <= man and man < 1.0:
        man *= 2
        e -= 1
    if sane_float(man,e):
        man -= 1
        e += bias
        mantissa = int(2**prec *(man) +0.5)
        res=[]
        if mantissa >> prec :
            mantissa = 0
            e += 1

        for i in range(size-2):
            #res += [ mantissa & 0xff]
            res.extend([ mantissa & 0xff])
            mantissa >>= 8
        #res += [ (mantissa & (2**(15-exp)-1)) | ((e & (2**(exp-7)-1))<<(15-exp))]
        res.extend([ (mantissa & (2**(15-exp)-1)) | ((e & (2**(exp-7)-1))<<(15-exp))])
        #res += [sign << 7 | e >> (exp - 7)]
        res.extend([sign << 7 | e >> (exp - 7)])
        if le == 'big':
            res.reverse()
        return ''.join([chr(x) for x in res])
    # TODO: What todo with insane floats/doubles. handle in sanefloat?

big_endian_format = {
    'x':{ 'size' : 1, 'alignment' : 0, 'pack' : None, 'unpack' : None},
    'b':{ 'size' : 1, 'alignment' : 0, 'pack' : pack_signed_int, 'unpack' : unpack_signed_int},
    'B':{ 'size' : 1, 'alignment' : 0, 'pack' : pack_unsigned_int, 'unpack' : unpack_int},
    'c':{ 'size' : 1, 'alignment' : 0, 'pack' : pack_char, 'unpack' : unpack_char},
    's':{ 'size' : 1, 'alignment' : 0, 'pack' : None, 'unpack' : None},
    'p':{ 'size' : 1, 'alignment' : 0, 'pack' : None, 'unpack' : None},
    'h':{ 'size' : 2, 'alignment' : 0, 'pack' : pack_signed_int, 'unpack' : unpack_signed_int},
    'H':{ 'size' : 2, 'alignment' : 0, 'pack' : pack_unsigned_int, 'unpack' : unpack_int},
    'i':{ 'size' : 4, 'alignment' : 0, 'pack' : pack_signed_int, 'unpack' : unpack_signed_int},
    'I':{ 'size' : 4, 'alignment' : 0, 'pack' : pack_unsigned_int, 'unpack' : unpack_int},
    'l':{ 'size' : 4, 'alignment' : 0, 'pack' : pack_signed_int, 'unpack' : unpack_signed_int},
    'L':{ 'size' : 4, 'alignment' : 0, 'pack' : pack_unsigned_int, 'unpack' : unpack_int},
    'q':{ 'size' : 8, 'alignment' : 0, 'pack' : pack_signed_int, 'unpack' : unpack_signed_int},
    'Q':{ 'size' : 8, 'alignment' : 0, 'pack' : pack_unsigned_int, 'unpack' : unpack_int},
    'f':{ 'size' : 4, 'alignment' : 0, 'pack' : pack_float, 'unpack' : unpack_float},
    'd':{ 'size' : 8, 'alignment' : 0, 'pack' : pack_float, 'unpack' : unpack_float},
    }
default = big_endian_format
formatmode={ '<' : (default, 'little'),
             '>' : (default, 'big'),
             '!' : (default, 'big'),
             '=' : (default, sys.byteorder),
             '@' : (default, sys.byteorder)
            }

def getmode(fmt):
    try:
        formatdef,endianness = formatmode[fmt[0]]
        index = 1
    except KeyError:
        formatdef,endianness = formatmode['@']
        index = 0
    return formatdef,endianness,index
def getNum(fmt,i):
    num=None
    cur = fmt[i]
    while ('0'<= cur ) and ( cur <= '9'):
        if num == None:
            num = int(cur)
        else:
            num = 10*num + int(cur)
        i += 1
        cur = fmt[i]
    return num,i

def calcsize(fmt):
    """calcsize(fmt) -> int
    Return size of C struct described by format string fmt.
    See struct.__doc__ for more on format strings."""

    formatdef,endianness,i = getmode(fmt)
    num = 0
    result = 0
    while i<len(fmt):
        num,i = getNum(fmt,i)
        cur = fmt[i]
        try:
            format = formatdef[cur]
        except KeyError:
            raise StructError,"%s is not a valid format"%cur
        if num != None :
            result += num*format['size']
        else:
            result += format['size']
        num = 0
        i += 1
    return result

def pack(fmt,*args):
    """pack(fmt, v1, v2, ...) -> string
       Return string containing values v1, v2, ... packed according to fmt.
       See struct.__doc__ for more on format strings."""
    formatdef,endianness,i = getmode(fmt)
    args = list(args)
    n_args = len(args)
    result = []
    while i<len(fmt):
        num,i = getNum(fmt,i)
        cur = fmt[i]
        try:
            format = formatdef[cur]
        except KeyError:
            raise StructError,"%s is not a valid format"%cur
        if num == None :
            num_s = 0
            num = 1
        else:
            num_s = num

        if cur == 'x':
            #result += ['\0'*num]
            result.extend(["".ljust(num, '\0')])
        elif cur == 's':
            if isinstance(args[0], str):
                padding = num - len(args[0])
                #result += [args[0][:num] + '\0'*padding]
                result.extend([args[0][:num] + "".ljust(padding, '\0')])
                args.pop(0)
            else:
                raise StructError,"arg for string format not a string"
        elif cur == 'p':
            if isinstance(args[0], str):
                padding = num - len(args[0]) - 1

                if padding > 0:
                    #result += [chr(len(args[0])) + args[0][:num-1] + '\0'*padding]
                    result.extend([chr(len(args[0])) + args[0][:num-1] + "".ljust(padding, '\0')])
                else:
                    if num<255:
                        #result += [chr(num-1) + args[0][:num-1]]
                        result.extend([chr(num-1) + args[0][:num-1]])
                    else:
                        #result += [chr(255) + args[0][:num-1]]
                        result.extend([chr(255) + args[0][:num-1]])
                args.pop(0)
            else:
                raise StructError,"arg for string format not a string"

        else:
            if len(args) < num:
                raise StructError,"insufficient arguments to pack"
            for var in args[:num]:
                #result += [format['pack'](var,format['size'],endianness)]
                result.extend([format['pack'](var,format['size'],endianness)])
            args=args[num:]
        num = None
        i += 1
    if len(args) != 0:
        raise StructError,"too many arguments for pack format"
    return ''.join(result)

def unpack(fmt,data):
    """unpack(fmt, string) -> (v1, v2, ...)
       Unpack the string, containing packed C structure data, according
       to fmt.  Requires len(string)==calcsize(fmt).
       See struct.__doc__ for more on format strings."""
    formatdef,endianness,i = getmode(fmt)
    j = 0
    num = 0
    result = []
    length= calcsize(fmt)
    if length != len (data):
        raise StructError,"unpack str size does not match format"
    while i<len(fmt):
        num,i=getNum(fmt,i)
        cur = fmt[i]
        i += 1
        try:
            format = formatdef[cur]
        except KeyError:
            raise StructError,"%s is not a valid format"%cur

        if not num :
            num = 1

        if cur == 'x':
            j += num
        elif cur == 's':
            result.append(data[j:j+num])
            j += num
        elif cur == 'p':
            n=ord(data[j])
            if n >= num:
                n = num-1
            result.append(data[j+1:j+n+1])
            j += num
        else:
            for n in range(num):
                #result += [format['unpack'](data,j,format['size'],endianness)]
                result.extend([format['unpack'](data,j,format['size'],endianness)])
                j += format['size']

    return tuple(result)

def pack_into(fmt, buf, offset, *args):
    raise NotImplementedError("pack_into")
    #data = pack(fmt, *args)
    #buffer(buf)[offset:offset+len(data)] = data

def unpack_from(fmt, buf, offset=0):
    raise NotImplementedError("unpack_from")
    #size = calcsize(fmt)
    #data = buffer(buf)[offset:offset+size]
    #if len(data) != size:
    #    raise error("unpack_from requires a buffer of at least %d bytes"
    #                % (size,))
    #return unpack(fmt, data)
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.