PyXR

c:\projects\bitpim\src \ prototypeslg.py



0001 ### BITPIM
0002 ###
0003 ### Copyright (C) 2003-2005 Roger Binns <rogerb@rogerbinns.com>
0004 ###
0005 ### This program is free software; you can redistribute it and/or modify
0006 ### it under the terms of the BitPim license as detailed in the LICENSE file.
0007 ###
0008 ### $Id: prototypeslg.py 4633 2008-07-05 05:04:50Z djpham $
0009 
0010 import bpcalendar
0011 
0012 import calendar
0013 import prototypes
0014 import re
0015 import time
0016 
0017 class LGCALDATE(prototypes.UINTlsb):
0018     def __init__(self, *args, **kwargs):
0019         """A date/time as used in the LG calendar"""
0020         super(LGCALDATE,self).__init__(*args, **kwargs)
0021         self._valuedate=(0,0,0,0,0)  # year month day hour minute
0022 
0023         dict={'sizeinbytes': 4}
0024         dict.update(kwargs)
0025 
0026         if self._ismostderived(LGCALDATE):
0027             self._update(args, dict)
0028 
0029     def _update(self, args, kwargs):
0030         for k in 'constant', 'default', 'value':
0031             if kwargs.has_key(k):
0032                 kwargs[k]=self._converttoint(kwargs[k])
0033         if len(args)==0:
0034             pass
0035         elif len(args)==1:
0036             args=(self._converttoint(args[0]),)
0037         else:
0038             raise TypeError("expected (year,month,day,hour,minute) as arg")
0039 
0040         super(LGCALDATE,self)._update(args, kwargs) # we want the args
0041         self._complainaboutunusedargs(LGCALDATE,kwargs)
0042         assert self._sizeinbytes==4
0043 
0044     def getvalue(self):
0045         """Unpack 32 bit value into date/time
0046 
0047         @rtype: tuple
0048         @return: (year, month, day, hour, minute)
0049         """
0050         val=super(LGCALDATE,self).getvalue()
0051         min=val&0x3f # 6 bits
0052         val>>=6
0053         hour=val&0x1f # 5 bits (uses 24 hour clock)
0054         val>>=5
0055         day=val&0x1f # 5 bits
0056         val>>=5
0057         month=val&0xf # 4 bits
0058         val>>=4
0059         year=val&0xfff # 12 bits
0060         return (year, month, day, hour, min)
0061 
0062     def _converttoint(self, date):
0063         assert len(date)==5
0064         year,month,day,hour,min=date
0065         if year>4095:
0066             year=4095
0067         val=year
0068         val<<=4
0069         val|=month
0070         val<<=5
0071         val|=day
0072         val<<=5
0073         val|=hour
0074         val<<=6
0075         val|=min
0076         return val
0077 
0078 class LGCALREPEAT(prototypes.UINTlsb):
0079     def __init__(self, *args, **kwargs):
0080         """A 32-bit bitmapped value used to store repeat info for events in the LG calendar"""
0081         super(LGCALREPEAT,self).__init__(*args, **kwargs)
0082         
0083         # The meaning of the bits in this field
0084         # MSB                          LSB
0085         #  3         2         1         
0086         # 10987654321098765432109876543210
0087         #                              210  repeat_type
0088         #                            0      exceptions, set to 1 if there are exceptions
0089         #                     6543210       dow_weekly (weekly repeat type)
0090         #                         210       dow (monthly repeat type)
0091         #             543210                interval
0092         #               3210                month_index
0093         #  543210                           day_index    
0094 
0095         # repeat_type: 0=none, 1=daily, 2=weekly, 3=monthly, 4=yearly, 5=weekdays, 6=XthDayEachMonth(e.g. 3rd Friday each month)
0096         # dow_weekly: Weekly repeat type only. Identical to bpcalender dow bits, multiple selections allowed(Bit0=sun,Bit1=mon,Bit2=tue,Bit3=wed,Bit4=thur,Bit5=fri,Bit6=sat)  
0097         # dow_monthly: Monthly repeat type 6 only. (0=sun,1=mon,2=tue,3=wed,4=thur,5=fri,6=sat)
0098         # interval: repeat interval, eg. every 1 week, 2 weeks 4 weeks etc. Also be used for months, but bp does not support this.
0099         # month_index: For type 4 this is the month the event starts in
0100         # day_index: For type 6 this represents the number of the day that is the repeat, e.g. "2"nd tuesday
0101         #            For type 3&4 this is the day of the month that the repeat occurs, usually the same as the start date.
0102         #            bp does not support this not being the support date
0103 
0104         dict={'sizeinbytes': 4}
0105         dict.update(kwargs)
0106 
0107         if self._ismostderived(LGCALREPEAT):
0108             self._update(args, dict)
0109 
0110     def _update(self, args, kwargs):
0111         for k in 'constant', 'default', 'value':
0112             if kwargs.has_key(k):
0113                 kwargs[k]=self._converttoint(kwargs[k])
0114         if len(args)==0:
0115             pass
0116         elif len(args)==1:
0117             args=(self._converttoint(args[0]),)
0118         else:
0119             raise TypeError("expected (type, dow, interval) as arg")
0120 
0121         super(LGCALREPEAT,self)._update(args, kwargs) # we want the args
0122         self._complainaboutunusedargs(LGCALDATE,kwargs)
0123         assert self._sizeinbytes==4
0124 
0125     def getvalue(self):
0126         val=super(LGCALREPEAT,self).getvalue()
0127         type=val&0x7 # 3 bits
0128         val>>=4
0129         exceptions=val&0x1
0130         val>>=1
0131         #get day of week, only valid for some repeat types
0132         #format of data is also different for different repeat types
0133         interval2=(val>>9)&0x3f
0134         if type==6: # for monthly repeats
0135             dow=self._to_bp_dow[val&7] #day of month, valid for monthly repeat types, need to convert to bitpim format
0136         elif type==2: #weekly 
0137             dow=val&0x7f # 7 bits, already matched bpcalender format
0138         else:
0139             dow=0
0140         # get interval
0141         if type==6:
0142             val>>=20
0143             interval=val&0x1f # day_index
0144         else:
0145             val>>=9
0146             interval=val&0x3f
0147         return (type, dow, interval, interval2, exceptions)
0148 
0149     _caldomvalues={
0150         0x01: 0x0, #sun
0151         0x02: 0x1, #mon
0152         0x04: 0x2, #tue
0153         0x08: 0x3, #wed
0154         0x10: 0x4, #thur
0155         0x20: 0x5, #fri
0156         0x40: 0x6  #sat
0157         }
0158     _to_bp_dow={
0159         0: 0x01,    # Sun
0160         1: 0x02,    # Mon
0161         2: 0x04,    # Tue
0162         3: 0x08,    # Wed
0163         4: 0x10,    # Thu
0164         5: 0x20,    # Fri
0165         6: 0x40,    # Sat
0166         }
0167         
0168     def _converttoint(self, repeat):
0169         if not isinstance(repeat, (tuple, list)):
0170             if __debug__:
0171                 raise TypeError
0172             else:
0173                 return 0
0174         if len(repeat)!=5:
0175             if __debug__:
0176                 raise ValueError
0177             else:
0178                 return 0
0179         type,dow,interval,interval2,exceptions=repeat
0180         val=0
0181         # construct bitmapped value for repeat
0182         # look for weekday type
0183         val=interval
0184         if type==6 or type==3:
0185             val<<=11
0186             val|=interval2
0187         if type==4: #yearly
0188             val<<=11
0189             val|=dow
0190         val<<=9
0191         if type==2:
0192             val|=dow
0193         elif type==6:
0194             if self._caldomvalues.has_key(dow):
0195                 val|=self._caldomvalues[dow]
0196             else:
0197                 # invalid day-of-week for monthly type, just bail
0198                 return 0
0199         val<<=1
0200         val|=exceptions
0201         val<<=4
0202         val|=type
0203         return val
0204 
0205 class GPSDATE(prototypes.UINTlsb):
0206     _time_t_ofs=calendar.timegm((1980, 1, 6, 0, 0, 0))
0207     _counter=0
0208     def __init__(self, *args, **kwargs):
0209         """A date/time as used in the LG call history files,
0210         @keyword unique: (True/False, Optional) Ensure that each GSPDATE instance
0211                           is unique.
0212         """
0213         super(GPSDATE, self).__init__(*args, **kwargs)
0214         self._unique=False
0215         dict={'sizeinbytes': 4}
0216         dict.update(kwargs)
0217 
0218         if self._ismostderived(GPSDATE):
0219             self._update(args, dict)
0220 
0221     def _update(self, args, kwargs):
0222         self._consumekw(kwargs, ('unique',))
0223         for k in 'constant', 'default', 'value':
0224             if kwargs.has_key(k):
0225                 kwargs[k]=self._converttoint(kwargs[k])
0226 
0227         if len(args)==0:
0228             pass
0229         elif len(args)==1:
0230             args=(self._converttoint(args[0]),)
0231         else:
0232             raise TypeError("expected (year,month,day,hour,minute,sec) as arg")
0233 
0234         super(GPSDATE, self)._update(args, kwargs) # we want the args
0235         self._complainaboutunusedargs(GPSDATE,kwargs)
0236         assert self._sizeinbytes==4
0237 
0238     def getvalue(self):
0239         """Convert 32 bit value into date/time
0240 
0241         @rtype: tuple
0242         @return: (year, month, day, hour, minute, sec)
0243         """
0244         return time.gmtime(self._time_t_ofs+super(GPSDATE, self).getvalue())[:6]
0245 
0246     def _converttoint(self, date):
0247         assert len(date)==6
0248         _val=calendar.timegm(date)-self._time_t_ofs
0249         if self._unique:
0250             _val+=GPSDATE._counter
0251             GPSDATE._counter+=1
0252             if GPSDATE._counter==0xffff:
0253                 GPSDATE._counter=0
0254         return _val
0255     @classmethod
0256     def now(_):
0257         return time.gmtime()[:6]
0258 
0259 class GSMCALDATE(prototypes.CSVSTRING):
0260     """ Represent date string with format "YYMMDD*"
0261     This format is being used in LG GSM Calendar Evetns
0262     """
0263     def __init__(self, *args, **kwargs):
0264         super(GSMCALDATE, self).__init__(*args, **kwargs)
0265         self._data=None
0266         self._readmode=True
0267         if self._ismostderived(GSMCALDATE):
0268             self._update(args, kwargs)
0269 
0270     def _set_data(self, v=None):
0271         if v:
0272             self._data=v[:3]
0273         else:
0274             self._data=(2000+int(self._value[:2]), int(self._value[2:4]),
0275                         int(self._value[4:6]))
0276     def _set_value(self):
0277         self._value='%02d%02d%02d'%(self._data[0]-2000, self._data[1],
0278                                     self._data[2])
0279 
0280     def _update(self, args, kwargs):
0281         self._consumekw(kwargs, ('readmode',))
0282         if len(args)==1:
0283             if isinstance(args[0], (list, tuple)):
0284                 super(GSMCALDATE, self)._update((), kwargs)
0285                 self._set_data(args[0])
0286                 self._set_value()
0287             elif isinstance(args[0], (str, unicode)):
0288                 super(GSMCALDATE, self)._update(args, kwargs)
0289                 self._set_data()
0290             else:
0291                 raise TypeError
0292         elif len(args)==0:
0293             super(GSMCALDATE, self)._update(args, kwargs)
0294         else:
0295             raise TypeError
0296         self._complainaboutunusedargs(GSMCALDATE, kwargs)
0297 
0298     def readfrombuffer(self, buf):
0299         super(GSMCALDATE, self).readfrombuffer(buf)
0300         if self._value:
0301             self._set_data()
0302         else:
0303             self._data=None
0304 
0305     def getvalue(self):
0306         """Returns the tuple of (year, month, day)"""
0307         if self._data is None:
0308             if self._value is None:
0309                 raise prototypes.ValueNotSetException()
0310             self._set_data()
0311         if self._readmode:
0312             return self._data
0313         else:
0314             if self._quotechar:
0315                 _quote=chr(self._quotechar)
0316             else:
0317                 _quote=''
0318             return _quote+self._value+_quote
0319 
0320 class GSMCALTIME(GSMCALDATE):
0321     """ Represent date time with format "hhm"
0322     This format is being used in LG GSM Calendar Evetns
0323     """
0324 
0325     def __init__(self, *args, **kwargs):
0326         super(GSMCALTIME, self).__init__(*args, **kwargs)
0327         if self._ismostderived(GSMCALTIME):
0328             self._update(args, kwargs)
0329 
0330     def _set_data(self, v=None):
0331         if v:
0332             self._data=v[:2]
0333         else:
0334             self._data=(int(self._value[:2]), int(self._value[2:4]))
0335 
0336     def _set_value(self):
0337         self._value='%02d%02d'%self._data
0338 
0339 class SMSDATETIME(prototypes.CSVSTRING):
0340     """ Represent date time with the format 'yy/MM/dd,hh:mm:ss+-zz' used
0341     by GSM SMS messages.
0342     Currently works only 1 way: SMS Date Time -> ISO String
0343     """
0344     _re_pattern='^\d\d/\d\d/\d\d,\d\d:\d\d:\d\d[+\-]\d\d$'
0345     _re_compiled_pattern=None
0346     def __init__(self, *args, **kwargs):
0347         if SMSDATETIME._re_compiled_pattern is None:
0348             SMSDATETIME._re_compiled_pattern=re.compile(SMSDATETIME._re_pattern)
0349         super(SMSDATETIME, self).__init__(*args, **kwargs)
0350         if self._ismostderived(SMSDATETIME):
0351             self._update(args, kwargs)
0352 
0353     def _update(self, args, kwargs):
0354         super(SMSDATETIME, self)._update(args, kwargs)
0355         if self._value and \
0356            not re.match(SMSDATETIME._re_compiled_pattern, self._value):
0357             raise ValueError('COrrect Format: yy/MM/dd,hh:mm:ss+-zz')
0358 
0359     def getvalue(self):
0360         """Returns the ISO Format 'YYYMMDDTHHMMSS+-mmss'"""
0361         if self._value:
0362             _s=self._value.split(',')
0363             return '20%sT%s00'%(_s[0].replace('/', ''),
0364                                 _s[1].replace(':', ''))
0365 
0366 class TELUSLGCALREPEAT(prototypes.UINTlsb):
0367     def __init__(self, *args, **kwargs):
0368         """A 32-bit bitmapped value used to store repeat info for events in the LG calendar"""
0369         super(TELUSLGCALREPEAT,self).__init__(*args, **kwargs)
0370         
0371         # The meaning of the bits in this field
0372         # MSB                          LSB
0373         #  3         2         1         
0374         # 10987654321098765432109876543210
0375         #                              210  repeat_type
0376         #                            0      exceptions, set to 1 if there are exceptions
0377         #                     6543210       dow_weekly (weekly repeat type)
0378         #                         210       dow (monthly repeat type)
0379         #             543210                interval
0380         #               3210                month_index
0381         # 6543210                           day_index    
0382 
0383         # repeat_type: 0=none, 1=daily, 2=weekdays, 3=weekly, 4=Month Nth Xday, 5=monthly on date, 6=yearly Nth Xday in month, 7=yearly on date 
0384         # dow_weekly: Weekly repeat type only. Identical to bpcalender dow bits, multiple selections allowed(Bit0=sun,Bit1=mon,Bit2=tue,Bit3=wed,Bit4=thur,Bit5=fri,Bit6=sat)  
0385         # dow_monthly: Monthly repeat type 6 only. (0=sun,1=mon,2=tue,3=wed,4=thur,5=fri,6=sat)
0386         # interval: repeat interval, eg. every 1 week, 2 weeks 4 weeks etc. Also be used for months, but bp does not support this.
0387         # month_index: For type 4 this is the month the event starts in
0388         # day_index: For type 6 this represents the number of the day that is the repeat, e.g. "2"nd tuesday
0389         #            For type 3&4 this is the day of the month that the repeat occurs, usually the same as the start date.
0390         #            For type 0&2 set to 0x7F
0391         #            For type 1&3 set to 0
0392 
0393         dict={'sizeinbytes': 4}
0394         dict.update(kwargs)
0395 
0396         if self._ismostderived(TELUSLGCALREPEAT):
0397             self._update(args, dict)
0398 
0399     def _update(self, args, kwargs):
0400         for k in 'constant', 'default', 'value':
0401             if kwargs.has_key(k):
0402                 kwargs[k]=self._converttoint(kwargs[k])
0403         if len(args)==0:
0404             pass
0405         elif len(args)==1:
0406             args=(self._converttoint(args[0]),)
0407         else:
0408             raise TypeError("expected (type, dow, interval) as arg")
0409 
0410         super(TELUSLGCALREPEAT,self)._update(args, kwargs) # we want the args
0411         self._complainaboutunusedargs(TELUSLGCALREPEAT,kwargs)
0412         assert self._sizeinbytes==4
0413 
0414     def getvalue(self):
0415         val=super(TELUSLGCALREPEAT,self).getvalue()
0416         type=val&0x7 # 3 bits
0417         val>>=4
0418         exceptions=val&0x1
0419         val>>=1
0420         #get day of week, only valid for some repeat types
0421         #format of data is also different for different repeat types
0422         interval2=(val>>9)&0x3f
0423         if type==4: # for monthly repeats
0424             dow=self._to_bp_dow[val&7] #day of month, valid for monthly repeat types, need to convert to bitpim format
0425         elif type==3: #weekly 
0426             dow=val&0x7f # 7 bits, already matched bpcalender format
0427         else:
0428             dow=0
0429         # get interval
0430         if type==4:
0431             val>>=20
0432             interval=val&0x1f # day_index
0433         else:
0434             val>>=9
0435             interval=val&0x3f
0436         return (type, dow, interval, interval2, exceptions)
0437 
0438     _caldomvalues={
0439         0x01: 0x0, #sun
0440         0x02: 0x1, #mon
0441         0x04: 0x2, #tue
0442         0x08: 0x3, #wed
0443         0x10: 0x4, #thur
0444         0x20: 0x5, #fri
0445         0x40: 0x6  #sat
0446         }
0447     _to_bp_dow={
0448         0: 0x01,    # Sun
0449         1: 0x02,    # Mon
0450         2: 0x04,    # Tue
0451         3: 0x08,    # Wed
0452         4: 0x10,    # Thu
0453         5: 0x20,    # Fri
0454         6: 0x40,    # Sat
0455         }
0456         
0457     def _converttoint(self, repeat):
0458         if not isinstance(repeat, (tuple, list)):
0459             if __debug__:
0460                 raise TypeError
0461             else:
0462                 return 0
0463         if len(repeat)!=5:
0464             if __debug__:
0465                 raise ValueError
0466             else:
0467                 return 0
0468         type,dow,interval,interval2,exceptions=repeat
0469         val=0
0470         # construct bitmapped value for repeat
0471         val=interval
0472         if type==0 or type==2:
0473             val=0x7F
0474             val<<=11
0475             val|=interval
0476         if type==4 or type==5:
0477             val<<=11
0478             val|=interval2
0479         if type==7: #yearly
0480             val<<=11
0481             val|=dow
0482         val<<=9
0483         if type==2:
0484             val|=dow
0485         elif type==4:
0486             val|=self._caldomvalues[dow]
0487         val<<=1
0488         val|=exceptions
0489         val<<=4
0490         val|=type
0491         return val
0492 
0493 #-------------------------------------------------------------------------------
0494 class T9USERDBBLOCK(prototypes.BaseProtogenClass):
0495     """
0496     Special class to handle data blocks within the LG T9 User Database file.
0497     Perhaps, the prototypes syntax should be enhanced to more gracefully
0498     handle cases like this!
0499     """
0500 
0501     # known types of this block
0502     FreeBlock_Type='Free Block'
0503     A0_Type='A0 Block'
0504     WordsList_Type='Words List'
0505     C_Type='C'
0506     Garbage_Type='Garbage'
0507 
0508     def __init__(self, *args, **kwargs):
0509         super(T9USERDBBLOCK, self).__init__(*args, **kwargs)
0510         self._value=None
0511         self._type=None
0512         if self._ismostderived(T9USERDBBLOCK):
0513             self._update(args, kwargs)
0514 
0515     def _update(self, args, kwargs):
0516         super(T9USERDBBLOCK, self)._update(args, kwargs)
0517         # we have no special keywords to process so complain away
0518         self._complainaboutunusedargs(T9USERDBBLOCK, kwargs)
0519         # Set our value if one was specified
0520         if len(args)==0:
0521             pass
0522         elif len(args)==1:
0523             self._set_value(args[0])
0524         else:
0525             raise TypeError("Unexpected arguments "+`args`)
0526 
0527     def _set_value(self, v):
0528         # set the value of this block
0529         # the value must be a dict having 2 keys: 'type' and 'value'
0530         if not isinstance(v, dict):
0531             raise TypeError('Value must be a dict')
0532         if not v.has_key('type') or not v.has_key('value'):
0533             raise ValueError('Missing type or value keyword')
0534         _type=v['type']
0535         _value=v['value']
0536         if _type==self.FreeBlock_Type:
0537             # this is a free block, the value is an integer specifying
0538             # the length of this free block
0539             if not isinstance(_value, int):
0540                 raise TypeError('Value must be an int')
0541         elif _type==self.WordsList_Type:
0542             # this is a list of words, the value is a list of dicts,
0543             # each dict should have 2 keys: 'word', 'weight'.
0544             # value['word'] is a string
0545             # value['weight'] is an int, default to 0xA000
0546             if not isinstance(_value, list):
0547                 raise TypeError('Value must be a list of dicts')
0548         elif _type==self.A0_Type:
0549             _value=0xA0
0550         else:
0551             raise ValueError('Invalid type: '+_type)
0552         self._type=_type
0553         self._value=_value
0554 
0555     def _extract_words_list(self, buf):
0556         # read and construct a word list
0557         _res=[]
0558         _size=buf.peeknextbyte()
0559         while _size<0x80:
0560             _size=buf.getnextbyte()
0561             _weight=buf.getnextbyte()|(buf.getnextbyte()<<8)
0562             _res.append({ 'word': buf.getnextbytes(_size),
0563                           'weight': _weight })
0564             _size=buf.peeknextbyte()
0565         return _res
0566     def readfrombuffer(self, buf):
0567         try:
0568             self._bufferstartoffset=buf.getcurrentoffset()
0569             _ch=buf.peeknextbyte()
0570             if _ch&0xF0==0xC0:
0571                 self._type=self.C_Type
0572                 self._value=''
0573                 while True:
0574                     b=buf.getnextbytes(1)
0575                     self._value+=b
0576                     if b=='\x09':
0577                         self._value+=buf.getnextbytes(1)
0578                         break
0579             elif _ch&0xF0==0xA0:
0580                 self._type=self.A0_Type
0581                 self._value=buf.getnextbyte()
0582             elif _ch&0xF0==0x80:
0583                 self._type=self.FreeBlock_Type
0584                 self._value=((buf.getnextbyte()&0x0F)<<8)|buf.getnextbyte()
0585                 buf.getnextbytes(self._value-2)
0586             elif _ch<0x80:
0587                 self._type=self.WordsList_Type
0588                 self._value=self._extract_words_list(buf)
0589             else:
0590                 raise ValueError('Unknown block type: 0x%02X'%_ch)
0591         except IndexError:
0592             # ignore garbage at the end
0593             self._type=self.Garbage_Type
0594             self._value=0
0595 ##        print 'type:',self._type
0596 ##        print 'value:',self._value
0597         self._bufferendoffset=buf.getcurrentoffset()
0598 
0599     def getvalue(self):
0600         if self._value is None or self._type is None:
0601             raise ValueNotSetException()
0602         return { 'type': self._type,
0603                  'value': self._value }
0604 
0605     def packetsize(self):
0606         # return the size of this packet
0607         if self._value is None or self._type is None:
0608             raise ValueNotSetException()
0609         if self._type==self.C_Type or \
0610            self._type==self.A0_Type:
0611             return len(self._value)
0612         if self._type==self.FreeBlock_Type:
0613             return self._value
0614         if self._type==self.WordsList_Type:
0615             _size=0
0616             for _entry in self._value:
0617                 _size+=len(_entry['word'])+3
0618             return _size
0619 
0620     def writetobuffer(self, buf):
0621         if self._value is None or self._type is None:
0622             raise ValueNotSetException()
0623         self._bufferstartoffset=buf.getcurrentoffset()
0624         if self._type==self.C_Type:
0625             buf.appendbytes(self._value)
0626         elif self._type==self.A0_Type:
0627             buf.appendbyte(0xA0)
0628         elif self._type==self.FreeBlock_Type:
0629             buf.appendbyte(0x80|((self._value&0xF00)>>8))
0630             buf.appendbyte(self._value&0xff)
0631             for _ in range(self._value-2):
0632                 buf.appendbyte(0)
0633         elif self._type==self.WordsList_Type:
0634             for _entry in self._value:
0635                 buf.appendbyte(len(_entry['word']))
0636                 _weight=_entry.get('weight', 0xA000)
0637                 buf.appendbyte(_weight&0xff)
0638                 buf.appendbyte((_weight&0xFF00)>>8)
0639                 buf.appendbytes(_entry['word'])
0640         self._bufferendoffset=buf.getcurrentoffset()
0641 
0642 class LGHEXPN(prototypes.DATA):
0643     """ Phone numbers stored as hex. i.e. 0x5555551212f0 == 555-555-1212
0644     """
0645     def __init__(self, *args, **kwargs):
0646         """A date/time as used in the LG calendar"""
0647         super(LGHEXPN,self).__init__(*args, **kwargs)
0648         self._update(args, kwargs)
0649 
0650     def _update (self, args, kwargs):
0651         for k in 'constant', 'default', 'value':
0652             if kwargs.has_key(k):
0653                 kwargs[k]=self._string_to_lghexpn (kwargs[k])
0654         if len(args)==0:
0655             pass
0656         elif len(args)==1:
0657             args = (self._string_to_lghexpn (args[0]),)
0658         else:
0659             raise TypeError("Expected phone number string as arg")
0660 
0661         super(LGHEXPN,self)._update(args, kwargs)
0662 
0663     def _digit_to_char (self, digit):
0664         if digit <= 0x09:
0665             return chr (digit + ord('0'))
0666         elif digit == 0x0A:
0667             return '*'
0668         elif digit == 0x0B:
0669             return '#'
0670         elif digit == 0x0C:
0671             return 'W'
0672         elif digit == 0x0D:
0673             return 'P'
0674         else:
0675             # 0x0f is not an error
0676             raise
0677 
0678     def _char_to_digit (self, char):
0679         if char >= '0' and char <= '9':
0680             return ord(char) - ord('0')
0681         elif char == '*':
0682             return 0x0A
0683         elif char == '#':
0684             return 0x0B
0685         elif char == 'W':
0686             return 0x0C
0687         elif char == 'P':
0688             return 0x0D
0689         else:
0690             raise ValueError
0691 
0692     def _string_to_lghexpn (self, pn):
0693         val = ''
0694         
0695         byte = 0xf0
0696         for i in range(0, len (pn)):
0697             digit = self._char_to_digit (pn[i])
0698             if i % 2:
0699                 val += chr(byte & (0xf0 | digit))
0700                 byte = 0xf0
0701             else:
0702                 byte = (digit << 4) | 0x0f
0703         # write terminating byte
0704         val += chr(byte)
0705 
0706         return val
0707     
0708     def getvalue(self):
0709         """Unpack hex phone number
0710 
0711         @rtype: string
0712         @return: phone number
0713         """
0714         val=super(LGHEXPN,self).getvalue()
0715         pn = ''
0716         for byte in val:
0717             fd = ord(byte) >> 4
0718             sd = ord(byte) & 0x0f
0719 
0720             try:
0721                 pn += self._digit_to_char(fd)
0722                 pn += self._digit_to_char(sd)
0723             except:
0724                 # end of packed number, not an error
0725                 break
0726         return pn
0727 
0728 class PBDateTime(prototypes.BaseProtogenClass):
0729     "Handle  six 2-byte UINTs: y, m, d, h, m, s"
0730 
0731     def __init__(self, *args, **kwargs):
0732         """
0733         Class to handle the date/time format of 6 2-byte UINTs: y, m, d, h, m, s
0734         @keyword default: (Optional) Our default value
0735         @keyword defaulttocurrenttime: (Optional) Default to the current date/time
0736         """
0737         super(PBDateTime, self).__init__(*args, **kwargs)
0738         self._default=None
0739         self._defaulttocurrenttime=False
0740         self._value=None
0741 
0742         if self._ismostderived(PBDateTime):
0743             self._update(args, kwargs)
0744     
0745     def _update(self, args, kwargs):
0746         super(PBDateTime, self)._update(args, kwargs)
0747         self._consumekw(kwargs, ("default", "defaulttocurrenttime", "value"))
0748         self._complainaboutunusedargs(PBDateTime, kwargs)
0749 
0750         if len(args)==0:
0751             pass
0752         elif len(args)==1:
0753             self._value=args[0]
0754         else:
0755             raise TypeError("Unexpected arguments "+`args`)
0756 
0757         if self._value is None:
0758             # value not specified, check for either default or default to
0759             # current time
0760             if self._default:
0761                 self._value=self._default
0762             elif self._defaulttocurrenttime:
0763                 self._value=time.localtime()[:6]
0764 
0765     def readfrombuffer(self, buf):
0766         self._bufferstartoffset=buf.getcurrentoffset()
0767 
0768         _res=[]
0769         for i in range(6):
0770             _res.append(buf.getnextbyte()|(buf.getnextbyte()<<8))
0771         self._value=_res
0772 
0773         self._bufferendoffset=buf.getcurrentoffset()
0774 
0775     def writetobuffer(self, buf):
0776         if self._value is None:
0777             raise ValueNotSetException()
0778         if not isinstance(self._value, (list, tuple)):
0779             raise TypeError('value needs to be a list/tuple')
0780         if len(self._value)!=6:
0781             raise TypeError('len of value needs to be 6')
0782 
0783         self._bufferstartoffset=buf.getcurrentoffset()
0784         for _num in self._value:
0785             buf.appendbyte(_num&0xff)
0786             buf.appendbyte((_num>>8)&0xff)
0787         self._bufferendoffset=buf.getcurrentoffset()
0788 
0789     def packetsize(self):
0790         """Size in bytes"""
0791         return 12
0792 
0793     def getvalue(self):
0794         if self._value is None:
0795             raise ValueNotSetException()
0796         return self._value
0797 

Generated by PyXR 0.9.4