dbf.old._io

Package dbf :: Package old :: Module _io |
[hide private]

# Source Code for Module dbf.old._io

      1  """Routines for saving, retrieving, and creating fields"""
      2
      3  import struct
      4  from decimal import Decimal
      5  from dbf.exceptions import DbfError, DataOverflow
      6  from dbf.dates import Date, DateTime, Time
      7
      8
      9  # Constants
     10  VFPTIME = 1721425
     11
     12 -def packShortInt(value, bigendian=False):
     13          "Returns a two-bye integer from the value, or raises DbfError"
     14          # 256 / 65,536
     15          if value > 65535:
     16              raise DateOverflow("Maximum Integer size exceeded.  Possible: 65535.  Attempted: %d" % value)
     17          if bigendian:
     18              return struct.pack('>H', value)
     19          else:
     20              return struct.pack('<H', value)
     21 -def packLongInt(value, bigendian=False):
     22          "Returns a four-bye integer from the value, or raises DbfError"
     23          # 256 / 65,536 / 16,777,216
     24          if value > 4294967295:
     25              raise DateOverflow("Maximum Integer size exceeded.  Possible: 4294967295.  Attempted: %d" % value)
     26          if bigendian:
     27              return struct.pack('>L', value)
     28          else:
     29              return struct.pack('<L', value)
     30 -def packDate(date):
     31          "Returns a group of three bytes, in integer form, of the date"
     32          return "%c%c%c" % (date.year-1900, date.month, date.day)
     33 -def packStr(string):
     34          "Returns an 11 byte, upper-cased, null padded string suitable for field names; raises DbfError if the string is bigger than 10 bytes"
     35          if len(string) > 10:
     36              raise DbfError("Maximum string size is ten characters -- %s has %d characters" % (string, len(string)))
     37          return struct.pack('11s', string.upper())
     38 -def unpackShortInt(bytes, bigendian=False):
     39          "Returns the value in the two-byte integer passed in"
     40          if bigendian:
     41              return struct.unpack('>H', bytes)[0]
     42          else:
     43              return struct.unpack('<H', bytes)[0]
     44 -def unpackLongInt(bytes, bigendian=False):
     45          "Returns the value in the four-byte integer passed in"
     46          if bigendian:
     47              return int(struct.unpack('>L', bytes)[0])
     48          else:
     49              return int(struct.unpack('<L', bytes)[0])
     50 -def unpackDate(bytestr):
     51          "Returns a Date() of the packed three-byte date passed in"
     52          year, month, day = struct.unpack('<BBB', bytestr)
     53          year += 1900
     54          return Date(year, month, day)
     55 -def unpackStr(chars):
     56          "Returns a normal, lower-cased string from a null-padded byte string"
     57          return struct.unpack('%ds' % len(chars), chars)[0].replace('\x00','').lower()
     58 -def convertToBool(value):
     59      """Returns boolean true or false; normal rules apply to non-string values; string values
     60      must be 'y','t', 'yes', or 'true' (case insensitive) to be True"""
     61      if type(value) == str:
     62          return bool(value.lower() in ['t', 'y', 'true', 'yes'])
     63      else:
     64          return bool(value)
     65 -def unsupportedType(something, field, memo=None):
     66      "called if a data type is not supported for that style of table"
     67      raise DbfError('field type is not supported.')
     68 -def retrieveCharacter(bytes, fielddef={}, memo=None):
     69      "Returns the string in bytes with trailing white space removed"
     70      return bytes.tostring().rstrip()
     71 -def updateCharacter(string, fielddef, memo=None):
     72      "returns the string, truncating if string is longer than it's field"
     73      if type(string) != str:
     74          raise DbfError("incompatible type: %s" % type(string))
     75      return string.rstrip()
     76 -def retrieveCurrency(bytes, fielddef={}, memo=None):
     77      value = struct.unpack('<q', bytes)[0]
     78      return Decimal("%de-4" % value)
     79 -def updateCurrency(value, fielddef={}, memo=None):
     80      currency = int(value * 10000)
     81      if not -9223372036854775808 < currency < 9223372036854775808:
     82          raise DataOverflow("value %s is out of bounds" % value)
     83      return struct.pack('<q', currency)
     84 -def retrieveDate(bytes, fielddef={}, memo=None):
     85      "Returns the ascii coded date as a Date object"
     86      return Date.fromymd(bytes.tostring())
     87 -def updateDate(moment, fielddef={}, memo=None):
     88      "returns the Date or datetime.date object ascii-encoded (yyyymmdd)"
     89      if moment:
     90          return "%04d%02d%02d" % moment.timetuple()[:3]
     91      return '        '
     92 -def retrieveDouble(bytes, fielddef={}, memo=None):
     93      return struct.unpack('<d', bytes)[0]
     94 -def updateDouble(value, fielddef={}, memo=None):
     95      if not (type(value) in (int, long, float)):
     96          raise DbfError("incompatible type: %s" % type(value))
     97      return struct.pack('<d', value)
     98 -def retrieveInteger(bytes, fielddef={}, memo=None):
     99      "Returns the binary number stored in bytes in little-endian format"
    100      return struct.unpack('<i', bytes)[0]
    101 -def updateInteger(value, fielddef={}, memo=None):
    102      "returns value in little-endian binary format"
    103      if not (type(value) in (int, long)):
    104          raise DbfError("incompatible type: %s" % type(value))
    105      if not -2147483648 < value < 2147483647:
    106          raise DataOverflow("Integer size exceeded.  Possible: -2,147,483,648..+2,147,483,647.  Attempted: %d" % value)
    107      return struct.pack('<i', value)
    108 -def retrieveLogical(bytes, fielddef={}, memo=None):
    109      "Returns True if bytes is 't', 'T', 'y', or 'Y', None if '?', and False otherwise"
    110      bytes = bytes.tostring()
    111      if bytes == '?':
    112          return None
    113      return bytes in ['t','T','y','Y']
    114 -def updateLogical(logical, fielddef={}, memo=None):
    115      "Returs 'T' if logical is True, 'F' otherwise"
    116      if type(logical) != bool:
    117          logical = convertToBool(logical)
    118      if type(logical) <> bool:
    119          raise DbfError('Value %s is not logical.' % logical)
    120      return logical and 'T' or 'F'
    121 -def retrieveMemo(bytes, fielddef, memo):
    122      "Returns the block of data from a memo file"
    123      stringval = bytes.tostring()
    124      if stringval.strip():
    125          block = int(stringval.strip())
    126      else:
    127          block = 0
    128      return memo.get_memo(block, fielddef)
    129 -def updateMemo(string, fielddef, memo):
    130      "Writes string as a memo, returns the block number it was saved into"
    131      block = memo.put_memo(string)
    132      if block == 0:
    133          block = ''
    134      return "%*s" % (fielddef['length'], block)
    135 -def retrieveNumeric(bytes, fielddef, memo=None):
    136      "Returns the number stored in bytes as integer if field spec for decimals is 0, float otherwise"
    137      string = bytes.tostring()
    138      if string[0:1] == '*':  # value too big to store (Visual FoxPro idiocy)
    139          return None
    140      if not string.strip():
    141          string = '0'
    142      if fielddef['decimals'] == 0:
    143          return int(string)
    144      else:
    145          return float(string)
    146 -def updateNumeric(value, fielddef, memo=None):
    147      "returns value as ascii representation, rounding decimal portion as necessary"
    148      if not (type(value) in (int, long, float)):
    149          raise DbfError("incompatible type: %s" % type(value))
    150      decimalsize = fielddef['decimals']
    151      if decimalsize:
    152          decimalsize += 1
    153      maxintegersize = fielddef['length']-decimalsize
    154      integersize = len("%.0f" % value)
    155      if integersize > maxintegersize:
    156          raise DataOverflow('Integer portion too big')
    157      return "%*.*f" % (fielddef['length'], fielddef['decimals'], value)
    158 -def retrieveVfpDateTime(bytes, fielddef={}, memo=None):
    159      """returns the date/time stored in bytes; dates <= 01/01/1981 00:00:00
    160      may not be accurate;  BC dates are nulled."""
    161      # two four-byte integers store the date and time.
    162      # millesecords are discarded from time
    163      time = retrieveInteger(bytes[4:])
    164      microseconds = (time % 1000) * 1000
    165      time = time // 1000                      # int(round(time, -3)) // 1000 discard milliseconds
    166      hours = time // 3600
    167      mins = time % 3600 // 60
    168      secs = time % 3600 % 60
    169      time = Time(hours, mins, secs, microseconds)
    170      possible = retrieveInteger(bytes[:4])
    171      possible -= VFPTIME
    172      possible = max(0, possible)
    173      date = Date.fromordinal(possible)
    174      return DateTime.combine(date, time)
    175 -def updateVfpDateTime(moment, fielddef={}, memo=None):
    176      """sets the date/time stored in moment
    177      moment must have fields year, month, day, hour, minute, second, microsecond"""
    178      bytes = [0] * 8
    179      hour = moment.hour
    180      minute = moment.minute
    181      second = moment.second
    182      millisecond = moment.microsecond // 1000       # convert from millionths to thousandths
    183      time = ((hour * 3600) + (minute * 60) + second) * 1000 + millisecond
    184      bytes[4:] = updateInteger(time)
    185      bytes[:4] = updateInteger(moment.toordinal() + VFPTIME)
    186      return ''.join(bytes)
    187 -def retrieveVfpMemo(bytes, fielddef, memo):
    188      "Returns the block of data from a memo file"
    189      block = struct.unpack('<i', bytes)[0]
    190      return memo.get_memo(block, fielddef)
    191 -def updateVfpMemo(string, fielddef, memo):
    192      "Writes string as a memo, returns the block number it was saved into"
    193      block = memo.put_memo(string)
    194      return struct.pack('<i', block)
    195 -def addCharacter(format):
    196      if format[1] != '(' or format[-1] != ')':
    197          raise DbfError("Format for Character field creation is C(n), not %s" % format)
    198      length = int(format[2:-1])
    199      if not 0 < length < 255:
    200          raise ValueError
    201      decimals = 0
    202      return length, decimals
    203 -def addDate(format):
    204      length = 8
    205      decimals = 0
    206      return length, decimals
    207 -def addLogical(format):
    208      length = 1
    209      decimals = 0
    210      return length, decimals
    211 -def addMemo(format):
    212      length = 10
    213      decimals = 0
    214      return length, decimals
    215 -def addNumeric(format):
    216      if format[1] != '(' or format[-1] != ')':
    217          raise DbfError("Format for Numeric field creation is N(n,n), not %s" % format)
    218      length, decimals = format[2:-1].split(',')
    219      length = int(length)
    220      decimals = int(decimals)
    221      if not (0 < length < 18 and 0 <= decimals <= length - 2):
    222          raise ValueError
    223      return length, decimals
    224 -def addVfpCurrency(format):
    225      length = 8
    226      decimals = 0
    227      return length, decimals
    228 -def addVfpDateTime(format):
    229      length = 8
    230      decimals = 8
    231      return length, decimals
    232 -def addVfpDouble(format):
    233      length = 8
    234      decimals = 0
    235      return length, decimals
    236 -def addVfpInteger(format):
    237      length = 4
    238      decimals = 0
    239      return length, decimals
    240 -def addVfpMemo(format):
    241      length = 4
    242      decimals = 0
    243      return length, decimals
    244 -def addVfpNumeric(format):
    245      if format[1] != '(' or format[-1] != ')':
    246          raise DbfError("Format for Numeric field creation is N(n,n), not %s" % format)
    247      length, decimals = format[2:-1].split(',')
    248      length = int(length)
    249      decimals = int(decimals)
    250      if not (0 < length < 21 and 0 <= decimals <= length - 2):
    251          raise ValueError
    252      return length, decimals
    253