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 typ(bytes.tostring().rstrip())
73 "returns the string, truncating if string is longer than it's field"
74 string = str(string)
75 return string.rstrip()
77 value = struct.unpack('<q', bytes)[0]
78 return typ("%de-4" % value)
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)
85 "Returns the ascii coded date as a Date object"
86 return Date.fromymd(bytes.tostring())
88 "returns the Date or datetime.date object ascii-encoded (yyyymmdd)"
89 if moment:
90 return "%04d%02d%02d" % moment.timetuple()[:3]
91 return ' '
93 return float(struct.unpack('<d', bytes)[0])
95 return struct.pack('<d', float(value))
97 "Returns the binary number stored in bytes in little-endian format"
98 return typ(struct.unpack('<i', bytes)[0])
100 "returns value in little-endian binary format"
101 try:
102 value = int(value)
103 except Exception:
104 raise DbfError("incompatible type: %s(%s)" % (type(value), 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', int(value))
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']
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'
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)
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)
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] == '*':
139 return None
140 if not string.strip():
141 string = '0'
142 if typ == 'default':
143 if fielddef['decimals'] == 0:
144 return int(string)
145 else:
146 return float(string)
147 else:
148 return typ(string)
150 "returns value as ascii representation, rounding decimal portion as necessary"
151 try:
152 value = float(value)
153 except Exception:
154 raise DbfError("incompatible type: %s(%s)" % (type(value), value))
155 decimalsize = fielddef['decimals']
156 if decimalsize:
157 decimalsize += 1
158 maxintegersize = fielddef['length']-decimalsize
159 integersize = len("%.0f" % floor(value))
160 if integersize > maxintegersize:
161 raise DataOverflow('Integer portion too big')
162 return "%*.*f" % (fielddef['length'], fielddef['decimals'], value)
181 """sets the date/time stored in moment
182 moment must have fields year, month, day, hour, minute, second, microsecond"""
183 bytes = [0] * 8
184 hour = moment.hour
185 minute = moment.minute
186 second = moment.second
187 millisecond = moment.microsecond // 1000
188 time = ((hour * 3600) + (minute * 60) + second) * 1000 + millisecond
189 bytes[4:] = updateInteger(time)
190 bytes[:4] = updateInteger(moment.toordinal() + VFPTIME)
191 return ''.join(bytes)
193 "Returns the block of data from a memo file"
194 block = struct.unpack('<i', bytes)[0]
195 return memo.get_memo(block, fielddef)
197 "Writes string as a memo, returns the block number it was saved into"
198 block = memo.put_memo(string)
199 return struct.pack('<i', block)
201 if format[1] != '(' or format[-1] != ')':
202 raise DbfError("Format for Character field creation is C(n), not %s" % format)
203 length = int(format[2:-1])
204 if not 0 < length < 255:
205 raise ValueError
206 decimals = 0
207 return length, decimals
209 length = 8
210 decimals = 0
211 return length, decimals
213 length = 1
214 decimals = 0
215 return length, decimals
217 length = 10
218 decimals = 0
219 return length, decimals
221 if format[1] != '(' or format[-1] != ')':
222 raise DbfError("Format for Numeric field creation is N(n,n), not %s" % format)
223 length, decimals = format[2:-1].split(',')
224 length = int(length)
225 decimals = int(decimals)
226 if not 0 < length < 18:
227 raise ValueError
228 if decimals and not 0 < decimals <= length - 2:
229 raise ValueError
230 return length, decimals
232 length = 8
233 decimals = 0
234 return length, decimals
236 length = 8
237 decimals = 8
238 return length, decimals
240 length = 8
241 decimals = 0
242 return length, decimals
244 length = 4
245 decimals = 0
246 return length, decimals
248 length = 4
249 decimals = 0
250 return length, decimals
252 if format[1] != '(' or format[-1] != ')':
253 raise DbfError("Format for Numeric field creation is N(n,n), not %s" % format)
254 length, decimals = format[2:-1].split(',')
255 length = int(length)
256 decimals = int(decimals)
257 if not 0 < length < 21:
258 raise ValueError
259 if decimals and not 0 < decimals <= length - 2:
260 raise ValueError
261 return length, decimals
262