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 field = struct.unpack('%ds' % len(chars), chars)[0]
59 name = []
60 for ch in field:
61 if ch == '\x00':
62 break
63 name.append(ch.lower())
64 return ''.join(name)
66 """Returns boolean true or false; normal rules apply to non-string values; string values
67 must be 'y','t', 'yes', or 'true' (case insensitive) to be True"""
68 if type(value) == str:
69 return bool(value.lower() in ['t', 'y', 'true', 'yes'])
70 else:
71 return bool(value)
73 "called if a data type is not supported for that style of table"
74 raise DbfError('field type is not supported.')
76 "Returns the string in bytes with trailing white space removed"
77 return typ(bytes.tostring().rstrip())
79 "returns the string, truncating if string is longer than it's field"
80 string = str(string)
81 return string.rstrip()
83 value = struct.unpack('<q', bytes)[0]
84 return typ(("%de-4" % value).strip())
86 currency = int(value * 10000)
87 if not -9223372036854775808 < currency < 9223372036854775808:
88 raise DataOverflow("value %s is out of bounds" % value)
89 return struct.pack('<q', currency)
91 "Returns the ascii coded date as a Date object"
92 return Date.fromymd(bytes.tostring())
94 "returns the Date or datetime.date object ascii-encoded (yyyymmdd)"
95 if moment:
96 return "%04d%02d%02d" % moment.timetuple()[:3]
97 return ' '
99 return float(struct.unpack('<d', bytes)[0])
101 return struct.pack('<d', float(value))
103 "Returns the binary number stored in bytes in little-endian format"
104 if typ is None or typ == 'default':
105 return struct.unpack('<i', bytes)[0]
106 else:
107 return typ(struct.unpack('<i', bytes)[0])
109 "returns value in little-endian binary format"
110 try:
111 value = int(value)
112 except Exception:
113 raise DbfError("incompatible type: %s(%s)" % (type(value), value))
114 if not -2147483648 < value < 2147483647:
115 raise DataOverflow("Integer size exceeded. Possible: -2,147,483,648..+2,147,483,647. Attempted: %d" % value)
116 return struct.pack('<i', int(value))
118 "Returns True if bytes is 't', 'T', 'y', or 'Y', None if '?', and False otherwise"
119 bytes = bytes.tostring()
120 if bytes == '?':
121 return None
122 return bytes in ['t','T','y','Y']
124 "Returs 'T' if logical is True, 'F' otherwise"
125 if type(logical) != bool:
126 logical = convertToBool(logical)
127 if type(logical) <> bool:
128 raise DbfError('Value %s is not logical.' % logical)
129 return logical and 'T' or 'F'
131 "Returns the block of data from a memo file"
132 stringval = bytes.tostring()
133 if stringval.strip():
134 block = int(stringval.strip())
135 else:
136 block = 0
137 return memo.get_memo(block, fielddef)
139 "Writes string as a memo, returns the block number it was saved into"
140 block = memo.put_memo(string)
141 if block == 0:
142 block = ''
143 return "%*s" % (fielddef['length'], block)
145 "Returns the number stored in bytes as integer if field spec for decimals is 0, float otherwise"
146 string = bytes.tostring()
147 if string[0:1] == '*':
148 return None
149 if not string.strip():
150 string = '0'
151 if typ == 'default':
152 if fielddef['decimals'] == 0:
153 return int(string)
154 else:
155 return float(string)
156 else:
157 return typ(string.strip())
159 "returns value as ascii representation, rounding decimal portion as necessary"
160 try:
161 value = float(value)
162 except Exception:
163 raise DbfError("incompatible type: %s(%s)" % (type(value), value))
164 decimalsize = fielddef['decimals']
165 if decimalsize:
166 decimalsize += 1
167 maxintegersize = fielddef['length']-decimalsize
168 integersize = len("%.0f" % floor(value))
169 if integersize > maxintegersize:
170 raise DataOverflow('Integer portion too big')
171 return "%*.*f" % (fielddef['length'], fielddef['decimals'], value)
190 """sets the date/time stored in moment
191 moment must have fields year, month, day, hour, minute, second, microsecond"""
192 bytes = [0] * 8
193 hour = moment.hour
194 minute = moment.minute
195 second = moment.second
196 millisecond = moment.microsecond // 1000
197 time = ((hour * 3600) + (minute * 60) + second) * 1000 + millisecond
198 bytes[4:] = updateInteger(time)
199 bytes[:4] = updateInteger(moment.toordinal() + VFPTIME)
200 return ''.join(bytes)
202 "Returns the block of data from a memo file"
203 block = struct.unpack('<i', bytes)[0]
204 return memo.get_memo(block, fielddef)
206 "Writes string as a memo, returns the block number it was saved into"
207 block = memo.put_memo(string)
208 return struct.pack('<i', block)
210 if format[1] != '(' or format[-1] != ')':
211 raise DbfError("Format for Character field creation is C(n), not %s" % format)
212 length = int(format[2:-1])
213 if not 0 < length < 255:
214 raise ValueError
215 decimals = 0
216 return length, decimals
218 length = 8
219 decimals = 0
220 return length, decimals
222 length = 1
223 decimals = 0
224 return length, decimals
226 length = 10
227 decimals = 0
228 return length, decimals
230 if format[1] != '(' or format[-1] != ')':
231 raise DbfError("Format for Numeric field creation is N(n,n), not %s" % format)
232 length, decimals = format[2:-1].split(',')
233 length = int(length)
234 decimals = int(decimals)
235 if not 0 < length < 18:
236 raise ValueError
237 if decimals and not 0 < decimals <= length - 2:
238 raise ValueError
239 return length, decimals
241 length = 8
242 decimals = 0
243 return length, decimals
245 length = 8
246 decimals = 8
247 return length, decimals
249 length = 8
250 decimals = 0
251 return length, decimals
253 length = 4
254 decimals = 0
255 return length, decimals
257 length = 4
258 decimals = 0
259 return length, decimals
261 if format[1] != '(' or format[-1] != ')':
262 raise DbfError("Format for Numeric field creation is N(n,n), not %s" % format)
263 length, decimals = format[2:-1].split(',')
264 length = int(length)
265 decimals = int(decimals)
266 if not 0 < length < 21:
267 raise ValueError
268 if decimals and not 0 < decimals <= length - 2:
269 raise ValueError
270 return length, decimals
271