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).strip())
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 if typ is None or typ == 'default':
99 return struct.unpack('<i', bytes)[0]
100 else:
101 return typ(struct.unpack('<i', bytes)[0])
103 "returns value in little-endian binary format"
104 try:
105 value = int(value)
106 except Exception:
107 raise DbfError("incompatible type: %s(%s)" % (type(value), value))
108 if not -2147483648 < value < 2147483647:
109 raise DataOverflow("Integer size exceeded. Possible: -2,147,483,648..+2,147,483,647. Attempted: %d" % value)
110 return struct.pack('<i', int(value))
112 "Returns True if bytes is 't', 'T', 'y', or 'Y', None if '?', and False otherwise"
113 bytes = bytes.tostring()
114 if bytes == '?':
115 return None
116 return bytes in ['t','T','y','Y']
118 "Returs 'T' if logical is True, 'F' otherwise"
119 if type(logical) != bool:
120 logical = convertToBool(logical)
121 if type(logical) <> bool:
122 raise DbfError('Value %s is not logical.' % logical)
123 return logical and 'T' or 'F'
125 "Returns the block of data from a memo file"
126 stringval = bytes.tostring()
127 if stringval.strip():
128 block = int(stringval.strip())
129 else:
130 block = 0
131 return memo.get_memo(block, fielddef)
133 "Writes string as a memo, returns the block number it was saved into"
134 block = memo.put_memo(string)
135 if block == 0:
136 block = ''
137 return "%*s" % (fielddef['length'], block)
139 "Returns the number stored in bytes as integer if field spec for decimals is 0, float otherwise"
140 string = bytes.tostring()
141 if string[0:1] == '*':
142 return None
143 if not string.strip():
144 string = '0'
145 if typ == 'default':
146 if fielddef['decimals'] == 0:
147 return int(string)
148 else:
149 return float(string)
150 else:
151 return typ(string.strip())
153 "returns value as ascii representation, rounding decimal portion as necessary"
154 try:
155 value = float(value)
156 except Exception:
157 raise DbfError("incompatible type: %s(%s)" % (type(value), value))
158 decimalsize = fielddef['decimals']
159 if decimalsize:
160 decimalsize += 1
161 maxintegersize = fielddef['length']-decimalsize
162 integersize = len("%.0f" % floor(value))
163 if integersize > maxintegersize:
164 raise DataOverflow('Integer portion too big')
165 return "%*.*f" % (fielddef['length'], fielddef['decimals'], value)
184 """sets the date/time stored in moment
185 moment must have fields year, month, day, hour, minute, second, microsecond"""
186 bytes = [0] * 8
187 hour = moment.hour
188 minute = moment.minute
189 second = moment.second
190 millisecond = moment.microsecond // 1000
191 time = ((hour * 3600) + (minute * 60) + second) * 1000 + millisecond
192 bytes[4:] = updateInteger(time)
193 bytes[:4] = updateInteger(moment.toordinal() + VFPTIME)
194 return ''.join(bytes)
196 "Returns the block of data from a memo file"
197 block = struct.unpack('<i', bytes)[0]
198 return memo.get_memo(block, fielddef)
200 "Writes string as a memo, returns the block number it was saved into"
201 block = memo.put_memo(string)
202 return struct.pack('<i', block)
204 if format[1] != '(' or format[-1] != ')':
205 raise DbfError("Format for Character field creation is C(n), not %s" % format)
206 length = int(format[2:-1])
207 if not 0 < length < 255:
208 raise ValueError
209 decimals = 0
210 return length, decimals
212 length = 8
213 decimals = 0
214 return length, decimals
216 length = 1
217 decimals = 0
218 return length, decimals
220 length = 10
221 decimals = 0
222 return length, decimals
224 if format[1] != '(' or format[-1] != ')':
225 raise DbfError("Format for Numeric field creation is N(n,n), not %s" % format)
226 length, decimals = format[2:-1].split(',')
227 length = int(length)
228 decimals = int(decimals)
229 if not 0 < length < 18:
230 raise ValueError
231 if decimals and not 0 < decimals <= length - 2:
232 raise ValueError
233 return length, decimals
235 length = 8
236 decimals = 0
237 return length, decimals
239 length = 8
240 decimals = 8
241 return length, decimals
243 length = 8
244 decimals = 0
245 return length, decimals
247 length = 4
248 decimals = 0
249 return length, decimals
251 length = 4
252 decimals = 0
253 return length, decimals
255 if format[1] != '(' or format[-1] != ')':
256 raise DbfError("Format for Numeric field creation is N(n,n), not %s" % format)
257 length, decimals = format[2:-1].split(',')
258 length = int(length)
259 decimals = int(decimals)
260 if not 0 < length < 21:
261 raise ValueError
262 if decimals and not 0 < decimals <= length - 2:
263 raise ValueError
264 return length, decimals
265