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 from math import floor
8
9
10
11 VFPTIME = 1721425
12
14 "Returns a two-bye integer from the value, or raises DbfError"
15
16 if value > 65535:
17 raise DateOverflow("Maximum Integer size exceeded. Possible: 65535. Attempted: %d" % value)
18 if bigendian:
19 return struct.pack('>H', value)
20 else:
21 return struct.pack('<H', value)
23 "Returns a four-bye integer from the value, or raises DbfError"
24
25 if value > 4294967295:
26 raise DateOverflow("Maximum Integer size exceeded. Possible: 4294967295. Attempted: %d" % value)
27 if bigendian:
28 return struct.pack('>L', value)
29 else:
30 return struct.pack('<L', value)
32 "Returns a group of three bytes, in integer form, of the date"
33 return "%c%c%c" % (date.year-1900, date.month, date.day)
35 "Returns an 11 byte, upper-cased, null padded string suitable for field names; raises DbfError if the string is bigger than 10 bytes"
36 if len(string) > 10:
37 raise DbfError("Maximum string size is ten characters -- %s has %d characters" % (string, len(string)))
38 return struct.pack('11s', string.upper())
40 "Returns the value in the two-byte integer passed in"
41 if bigendian:
42 return struct.unpack('>H', bytes)[0]
43 else:
44 return struct.unpack('<H', bytes)[0]
46 "Returns the value in the four-byte integer passed in"
47 if bigendian:
48 return int(struct.unpack('>L', bytes)[0])
49 else:
50 return int(struct.unpack('<L', bytes)[0])
52 "Returns a Date() of the packed three-byte date passed in"
53 year, month, day = struct.unpack('<BBB', bytestr)
54 year += 1900
55 return Date(year, month, day)
57 "Returns a normal, lower-cased string from a null-padded byte string"
58 return struct.unpack('%ds' % len(chars), chars)[0].replace('\x00','').lower()
60 """Returns boolean true or false; normal rules apply to non-string values; string values
61 must be 'y','t', 'yes', or 'true' (case insensitive) to be True"""
62 if type(value) == str:
63 return bool(value.lower() in ['t', 'y', 'true', 'yes'])
64 else:
65 return bool(value)
67 "called if a data type is not supported for that style of table"
68 raise DbfError('field type is not supported.')
70 "Returns the string in bytes with trailing white space removed"
71 return bytes.tostring().rstrip()
73 "returns the string, truncating if string is longer than it's field"
74 if type(string) != str:
75 raise DbfError("incompatible type: %s" % type(string))
76 return string.rstrip()
78 value = struct.unpack('<q', bytes)[0]
79 return Decimal("%de-4" % value)
81 currency = int(value * 10000)
82 if not -9223372036854775808 < currency < 9223372036854775808:
83 raise DataOverflow("value %s is out of bounds" % value)
84 return struct.pack('<q', currency)
86 "Returns the ascii coded date as a Date object"
87 return Date.fromymd(bytes.tostring())
89 "returns the Date or datetime.date object ascii-encoded (yyyymmdd)"
90 if moment:
91 return "%04d%02d%02d" % moment.timetuple()[:3]
92 return ' '
94 return struct.unpack('<d', bytes)[0]
96 if not (type(value) in (int, long, float)):
97 raise DbfError("incompatible type: %s" % type(value))
98 return struct.pack('<d', value)
100 "Returns the binary number stored in bytes in little-endian format"
101 return struct.unpack('<i', bytes)[0]
103 "returns value in little-endian binary format"
104 if not (type(value) in (int, long)):
105 raise DbfError("incompatible type: %s" % type(value))
106 if not -2147483648 < value < 2147483647:
107 raise DataOverflow("Integer size exceeded. Possible: -2,147,483,648..+2,147,483,647. Attempted: %d" % value)
108 return struct.pack('<i', value)
110 "Returns True if bytes is 't', 'T', 'y', or 'Y', None if '?', and False otherwise"
111 bytes = bytes.tostring()
112 if bytes == '?':
113 return None
114 return bytes in ['t','T','y','Y']
116 "Returs 'T' if logical is True, 'F' otherwise"
117 if type(logical) != bool:
118 logical = convertToBool(logical)
119 if type(logical) <> bool:
120 raise DbfError('Value %s is not logical.' % logical)
121 return logical and 'T' or 'F'
123 "Returns the block of data from a memo file"
124 stringval = bytes.tostring()
125 if stringval.strip():
126 block = int(stringval.strip())
127 else:
128 block = 0
129 return memo.get_memo(block, fielddef)
131 "Writes string as a memo, returns the block number it was saved into"
132 block = memo.put_memo(string)
133 if block == 0:
134 block = ''
135 return "%*s" % (fielddef['length'], block)
137 "Returns the number stored in bytes as integer if field spec for decimals is 0, float otherwise"
138 string = bytes.tostring()
139 if string[0:1] == '*':
140 return None
141 if not string.strip():
142 string = '0'
143 if fielddef['decimals'] == 0:
144 return int(string)
145 else:
146 return float(string)
148 "returns value as ascii representation, rounding decimal portion as necessary"
149 if not (type(value) in (int, long, float)):
150 raise DbfError("incompatible type: %s" % type(value))
151 decimalsize = fielddef['decimals']
152 if decimalsize:
153 decimalsize += 1
154 maxintegersize = fielddef['length']-decimalsize
155 integersize = len("%.0f" % floor(value))
156 if integersize > maxintegersize:
157 raise DataOverflow('Integer portion too big')
158 return "%*.*f" % (fielddef['length'], fielddef['decimals'], value)
177 """sets the date/time stored in moment
178 moment must have fields year, month, day, hour, minute, second, microsecond"""
179 bytes = [0] * 8
180 hour = moment.hour
181 minute = moment.minute
182 second = moment.second
183 millisecond = moment.microsecond // 1000
184 time = ((hour * 3600) + (minute * 60) + second) * 1000 + millisecond
185 bytes[4:] = updateInteger(time)
186 bytes[:4] = updateInteger(moment.toordinal() + VFPTIME)
187 return ''.join(bytes)
189 "Returns the block of data from a memo file"
190 block = struct.unpack('<i', bytes)[0]
191 return memo.get_memo(block, fielddef)
193 "Writes string as a memo, returns the block number it was saved into"
194 block = memo.put_memo(string)
195 return struct.pack('<i', block)
197 if format[1] != '(' or format[-1] != ')':
198 raise DbfError("Format for Character field creation is C(n), not %s" % format)
199 length = int(format[2:-1])
200 if not 0 < length < 255:
201 raise ValueError
202 decimals = 0
203 return length, decimals
205 length = 8
206 decimals = 0
207 return length, decimals
209 length = 1
210 decimals = 0
211 return length, decimals
213 length = 10
214 decimals = 0
215 return length, decimals
217 if format[1] != '(' or format[-1] != ')':
218 raise DbfError("Format for Numeric field creation is N(n,n), not %s" % format)
219 length, decimals = format[2:-1].split(',')
220 length = int(length)
221 decimals = int(decimals)
222 if not 0 < length < 18:
223 raise ValueError
224 if decimals and not 0 < decimals <= length - 2:
225 raise ValueError
226 return length, decimals
228 length = 8
229 decimals = 0
230 return length, decimals
232 length = 8
233 decimals = 8
234 return length, decimals
236 length = 8
237 decimals = 0
238 return length, decimals
240 length = 4
241 decimals = 0
242 return length, decimals
244 length = 4
245 decimals = 0
246 return length, decimals
248 if format[1] != '(' or format[-1] != ')':
249 raise DbfError("Format for Numeric field creation is N(n,n), not %s" % format)
250 length, decimals = format[2:-1].split(',')
251 length = int(length)
252 decimals = int(decimals)
253 if not 0 < length < 21:
254 raise ValueError
255 if decimals and not 0 < decimals <= length - 2:
256 raise ValueError
257 return length, decimals
258