├── debian ├── compat ├── files ├── changelog ├── copyright ├── control └── rules ├── .gitignore ├── Makefile ├── test.py ├── setup.py └── pxpy.pyx /debian/compat: -------------------------------------------------------------------------------- 1 | 4 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | pxpy.c 3 | -------------------------------------------------------------------------------- /debian/files: -------------------------------------------------------------------------------- 1 | python-pxlib_0.0.1-1_i386.deb python optional 2 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | python-pxlib (0.0.1-1) unstable; urgency=low 2 | 3 | * Initial Release. 4 | 5 | -- Uwe Steinmann Thu, 12 Aug 2004 11:11:53 +0200 6 | 7 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This package was debianized by Uwe Steinmann on 2 | Thu, 12 Aug 2004 11:56:42 +0200. 3 | 4 | It was downloaded from http://pxlib.sourceforge.net 5 | 6 | Upstream Authors: Lele Gaifax 7 | 8 | Copyright: GPL 9 | 10 | On Debian GNU/Linux systems, the complete text of the GNU General 11 | Public License can be found in `/usr/share/common-licenses/GPL'. 12 | 13 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # -*- Makefile -*- 2 | # :Project: pxpy -- Makefile 3 | # :Source: $Source: /cvsroot/pxlib/bindings/python/Makefile,v $ 4 | # :Created: Sun, Apr 04 2004 00:13:57 CEST 5 | # :Author: Lele Gaifax 6 | # :Revision: $Revision: 1.2 $ by $Author: lele $ 7 | # :Date: $Date: 2004/07/19 14:38:04 $ 8 | # 9 | 10 | all: 11 | python Setup.py build_ext --inplace 12 | 13 | clean: 14 | rm -f *.c *.o *.so *~ core 15 | rm -rf build 16 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: python-pxlib 2 | Section: python 3 | Priority: optional 4 | Maintainer: Uwe Steinmann 5 | Build-Depends: debhelper (>> 4.0.0), po-debconf, pxlib-dev, python-dev (>= 2.3) 6 | Standards-Version: 3.6.1 7 | 8 | Package: python-pxlib 9 | Architecture: any 10 | Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends} 11 | Description: An extension to read and write Paradox databases 12 | This is the Python wrapper around the lower level pxlib, a library 13 | for reading and writing Paradox database files. 14 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | # -*- mode: python; coding: utf-8 -*- 3 | # :Project: pxpy -- silly tester 4 | # :Source: $Source: /cvsroot/pxlib/bindings/python/test.py,v $ 5 | # :Created: Thu, May 13 2004 01:48:30 CEST 6 | # :Author: Lele Gaifax 7 | # :Revision: $Revision: 1.2 $ by $Author: lele $ 8 | # :Date: $Date: 2004/07/19 14:38:04 $ 9 | # 10 | 11 | import pxpy 12 | 13 | t = pxpy.Table("test/Automezzi.DB") 14 | print t 15 | t.open() 16 | t.setPrimaryIndex("test/Automezzi.PX") 17 | t.setBlobFile("test/Automezzi.MB") 18 | 19 | print "Fields: ", t.getFieldsCount() 20 | 21 | record = t.record 22 | 23 | while t.readRecord(): 24 | for i in range(record.getFieldsCount()): 25 | f = record.fields[i] 26 | value = f.getValue() 27 | print "%s: %s" % (f.fname, value) 28 | print "=================================" 29 | 30 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- Python -*- -*- coding: iso-8859-1 -*- 2 | # :Project: pxpy -- Module setup 3 | # :Source: $Source: /cvsroot/pxlib/bindings/python/Setup.py,v $ 4 | # :Created: Sun, Apr 04 2004 00:14:12 CEST 5 | # :Author: Lele Gaifax 6 | # :Revision: $Revision: 1.3 $ by $Author: lele $ 7 | # :Date: $Date: 2004/07/19 23:04:35 $ 8 | # 9 | 10 | from distutils.core import setup 11 | from distutils.extension import Extension 12 | from Cython.Distutils import build_ext 13 | 14 | 15 | setup( 16 | name = 'python-pxlib', 17 | description = "Python wrapper around pxlib", 18 | version = '0.0.1', 19 | author = "Lele Gaifax", 20 | author_email = "lele@nautilus.homeip.net", 21 | url = "http://pxlib.sourceforge.net/", 22 | 23 | ext_modules=[ 24 | Extension("pxpy", ["pxpy.pyx"], 25 | # Uncomment, to use current version 26 | #include_dirs=["../../pxlib/include/"], 27 | #library_dirs=["../../pxlib/src/.libs"], 28 | libraries=["px"]), 29 | ], 30 | cmdclass = {'build_ext': build_ext} 31 | ) 32 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # Sample debian/rules that uses debhelper. 3 | # GNU copyright 1997 to 1999 by Joey Hess. 4 | 5 | # Uncomment this to turn on verbose mode. 6 | #export DH_VERBOSE=1 7 | 8 | PYTHON=/usr/bin/python 9 | PYTHONVERION=`$(PYTHON) -V 2>&1|cut -d ' ' -f 2|cut -d. -f1-2` 10 | 11 | configure: configure-stamp 12 | configure-stamp: 13 | dh_testdir 14 | # Add here commands to configure the package. 15 | touch configure-stamp 16 | 17 | build: build-stamp 18 | 19 | build-stamp: configure-stamp 20 | dh_testdir 21 | 22 | # Add here commands to compile the package. 23 | $(PYTHON) Setup.py build 24 | touch build-stamp 25 | 26 | clean: 27 | dh_testdir 28 | dh_testroot 29 | rm -f build-stamp configure-stamp 30 | 31 | # Add here commands to clean up after the build process. 32 | $(PYTHON) Setup.py clean 33 | rm -rf build 34 | rm -rf dist 35 | rm -f MANIFEST 36 | 37 | dh_clean 38 | 39 | install: build 40 | dh_testdir 41 | dh_testroot 42 | dh_clean -k 43 | dh_installdirs 44 | 45 | # Add here commands to install the package into debian/$PACKAGE_NAME. 46 | mkdir -p $(CURDIR)/debian/python-pxlib/usr/lib/python$(PYTHONVERION)/site-packages/ 47 | cp build/lib.*/* $(CURDIR)/debian/python-pxlib/usr/lib/python$(PYTHONVERION)/site-packages/ 48 | 49 | # Build architecture-independent files here. 50 | binary-indep: build install 51 | # We have nothing to do by default. 52 | 53 | # Build architecture-dependent files here. 54 | binary-arch: build install 55 | dh_testdir 56 | dh_testroot 57 | dh_installchangelogs 58 | dh_installdocs 59 | dh_installexamples 60 | # dh_install --sourcedir=debian/$(PACKAGE_NAME) 61 | # dh_installmenu 62 | dh_installdebconf 63 | # dh_installlogrotate 64 | # dh_installemacsen 65 | # dh_installpam 66 | # dh_installmime 67 | # dh_installinit 68 | # dh_installcron 69 | # dh_installinfo 70 | # dh_installman 71 | # dh_link 72 | dh_strip 73 | dh_compress 74 | # dh_fixperms 75 | # dh_perl 76 | dh_python 77 | # dh_makeshlibs 78 | dh_installdeb 79 | dh_shlibdeps 80 | dh_gencontrol 81 | dh_md5sums 82 | dh_builddeb 83 | 84 | binary: binary-indep binary-arch 85 | .PHONY: build clean binary-indep binary-arch binary install configure 86 | -------------------------------------------------------------------------------- /pxpy.pyx: -------------------------------------------------------------------------------- 1 | # -*- Pyrex -*- 2 | # :Project: pxpy -- Python wrapper around pxlib 3 | # :Source: $Source: /cvsroot/pxlib/bindings/python/pxpy.pyx,v $ 4 | # :Created: Sun, Apr 04 2004 00:20:28 CEST 5 | # :Author: Lele Gaifax 6 | # :Revision: $Revision: 1.6 $ by $Author: lele $ 7 | # :Date: $Date: 2004/09/25 01:18:17 $ 8 | # 9 | 10 | """ 11 | Python wrapper around pxlib. 12 | 13 | This module, written in Pyrex_, allow to read data from Paradox tables 14 | using the pxlib_ library. 15 | 16 | .. _pyrex: http://www.cosc.canterbury.ac.nz/~greg/python/Pyrex/ 17 | .. _pxlib: http://pxlib.sourceforge.net/ 18 | """ 19 | 20 | import datetime 21 | 22 | import sys 23 | 24 | from libc.stdlib cimport * 25 | cdef extern from "stdlib.h" nogil: 26 | void *memset(void *str, int c, size_t n) 27 | void *memcpy(void *str1, void *str2, size_t n) 28 | 29 | cdef extern from "Python.h": 30 | object PyString_FromStringAndSize(char *s, int len) 31 | object PyString_Decode(char *s, int len, char *encoding, char *errors) 32 | object PyString_FromStringAndSize(char *v, int len) 33 | object PyString_AsDecodedObject(object str, char *encoding, char *errors) 34 | 35 | 36 | cdef extern from "string.h": 37 | int strnlen(char *s, int maxlen) 38 | 39 | cdef extern from "paradox.h": 40 | ctypedef enum fieldtype_t: 41 | pxfAlpha = 0x01 42 | pxfDate = 0x02 43 | pxfShort = 0x03 44 | pxfLong = 0x04 45 | pxfCurrency = 0x05 46 | pxfNumber = 0x06 47 | pxfLogical = 0x09 48 | pxfMemoBLOb = 0x0C 49 | pxfBLOb = 0x0D 50 | pxfFmtMemoBLOb = 0x0E 51 | pxfOLE = 0x0F 52 | pxfGraphic = 0x10 53 | pxfTime = 0x14 54 | pxfTimestamp = 0x15 55 | pxfAutoInc = 0x16 56 | pxfBCD = 0x17 57 | pxfBytes = 0x18 58 | pxfNumTypes = 0x18 59 | 60 | ctypedef enum filetype_t: 61 | pxfFileTypIndexDB = 0 62 | pxfFileTypPrimIndex = 1 63 | pxfFileTypNonIndexDB = 2 64 | pxfFileTypNonIncSecIndex = 3 65 | pxfFileTypSecIndex = 4 66 | pxfFileTypIncSecIndex = 5 67 | pxfFileTypNonIncSecIndexG = 6 68 | pxfFileTypSecIndexG = 7 69 | pxfFileTypIncSecIndexG = 8 70 | 71 | ctypedef struct pxfield_t: 72 | char *px_fname 73 | char px_ftype 74 | int px_flen 75 | int px_fdc 76 | 77 | ctypedef struct pxhead_t: 78 | char *px_tablename 79 | int px_recordsize 80 | char px_filetype 81 | int px_fileversion 82 | int px_numrecords 83 | int px_theonumrecords 84 | int px_numfields 85 | int px_maxtablesize 86 | int px_headersize 87 | int px_fileblocks 88 | int px_firstblock 89 | int px_lastblock 90 | int px_indexfieldnumber 91 | int px_indexroot 92 | int px_numindexlevels 93 | int px_writeprotected 94 | int px_doscodepage 95 | int px_primarykeyfields 96 | char px_modifiedflags1 97 | char px_modifiedflags2 98 | char px_sortorder 99 | int px_autoinc 100 | int px_fileupdatetime 101 | char px_refintegrity 102 | pxfield_t *px_fields 103 | 104 | ctypedef struct pxdoc_t: 105 | char *px_name 106 | pxhead_t *px_head 107 | char *targetencoding 108 | void *(*malloc)(pxdoc_t *p, unsigned int size, char *caller) 109 | void (*free)(pxdoc_t *p, void *mem) 110 | 111 | ctypedef struct pxdatablockinfo_t 112 | ctypedef struct pxblob_t: 113 | char *px_name 114 | pxdoc_t * pxdoc 115 | 116 | ctypedef struct pxpindex_t 117 | ctypedef struct pxstream_t 118 | 119 | pxdoc_t *PX_new() 120 | pxdoc_t* PX_new2(void (*errorhandler)(pxdoc_t *p, int type, char *msg, void *data), 121 | void* (*allocproc)(pxdoc_t *p, size_t size, char *caller), 122 | void* (*reallocproc)(pxdoc_t *p, void *mem, size_t size, char *caller), 123 | void (*freeproc)(pxdoc_t *p, void *mem)) 124 | char *PX_strdup(pxdoc_t *pxdoc, char *str) 125 | int PX_open_file(pxdoc_t *pxdoc, char *filename) 126 | int PX_create_file(pxdoc_t *pxdoc, pxfield_t *px_fields, unsigned int numfields, char *filename, int type) 127 | int PX_read_primary_index(pxdoc_t *pindex) 128 | int PX_add_primary_index(pxdoc_t *pxdoc, pxdoc_t *pindex) 129 | int PX_set_targetencoding(pxdoc_t *pxdoc, char *encoding) 130 | int PX_set_inputencoding(pxdoc_t *pxdoc, char *encoding) 131 | int PX_set_parameter(pxdoc_t *pxdoc, char *name, char *value) 132 | int PX_set_value(pxdoc_t *pxdoc, char *name, float value) 133 | pxblob_t *PX_new_blob(pxdoc_t *pxdoc) 134 | int PX_open_blob_file(pxblob_t *pxdoc, char *filename) 135 | int PX_close(pxdoc_t *pxdoc) 136 | int PX_close_blob(pxblob_t *pxdoc) 137 | void *PX_get_record(pxdoc_t *pxdoc, int recno, void *data) 138 | void *PX_get_record2(pxdoc_t *pxdoc, int recno, void *data, int *deleted, pxdatablockinfo_t *pxdbinfo) 139 | int PX_get_data_alpha(pxdoc_t *pxdoc, void *data, int len, char **value) 140 | int PX_get_data_bytes(pxdoc_t *pxdoc, void *data, int len, char **value) 141 | int PX_get_data_double(pxdoc_t *pxdoc, void *data, int len, double *value) 142 | int PX_get_data_long(pxdoc_t *pxdoc, void *data, int len, long *value) 143 | int PX_get_data_short(pxdoc_t *pxdoc, void *data, int len, short int *value) 144 | int PX_get_data_byte(pxdoc_t *pxdoc, void *data, int len, char *value) 145 | 146 | int PX_put_record(pxdoc_t *pxdoc, char *data) 147 | 148 | void PX_put_data_alpha(pxdoc_t *pxdoc, char *data, int len, char *value) 149 | void PX_put_data_double(pxdoc_t *pxdoc, char *data, int len, double value) 150 | void PX_put_data_long(pxdoc_t *pxdoc, char *data, int len, int value) 151 | void PX_put_data_short(pxdoc_t *pxdoc, char *data, int len, short int value) 152 | 153 | char *PX_read_blobdata(pxblob_t *pxblob, void *data, int len, int *mod, int *blobsize) 154 | void PX_SdnToGregorian(long int sdn, int *pYear, int *pMonth, int *pDay) 155 | long int PX_GregorianToSdn(int year, int month, int day) 156 | 157 | cdef void errorhandler(pxdoc_t *p, int type, char *msg, void *data): 158 | print 'error', type, msg 159 | 160 | cdef class PXDoc: 161 | """ 162 | Basic wrapper to 'pxdoc_t' based objects. 163 | """ 164 | 165 | cdef pxdoc_t *doc 166 | cdef char *filename 167 | cdef char isopen 168 | 169 | def __init__(self, filename): 170 | """ 171 | Create a PXDoc instance, associated to the given external filename. 172 | """ 173 | 174 | self.filename = filename 175 | self.doc = PX_new2(&errorhandler, NULL, NULL, NULL) 176 | self.isopen = 0 177 | 178 | def open(self): 179 | """ 180 | Open the data file. 181 | """ 182 | 183 | if PX_open_file(self.doc, self.filename)<0: 184 | raise Exception("Couldn't open `%s`" % self.filename) 185 | self.isopen = 1 186 | 187 | def close(self): 188 | """ 189 | Close the data file if needed. 190 | """ 191 | 192 | if self.isopen: 193 | PX_close(self.doc) 194 | self.isopen = 0 195 | 196 | def setTargetEncoding(self, encoding): 197 | PX_set_targetencoding(self.doc, encoding) 198 | 199 | def setInputEncoding(self, encoding): 200 | PX_set_inputencoding(self.doc, encoding) 201 | 202 | def setValue(self, parameter, value): 203 | PX_set_value(self.doc, parameter, value) 204 | 205 | def setParameter(self, parameter, value): 206 | PX_set_parameter(self.doc, parameter, value) 207 | 208 | def __dealloc__(self): 209 | """ 210 | Close the data file 211 | """ 212 | 213 | self.close() 214 | 215 | 216 | cdef class BlobFile: 217 | """ 218 | External BLOb file. 219 | """ 220 | 221 | cdef pxblob_t *blob 222 | cdef char *filename 223 | cdef char isopen 224 | 225 | def __init__(self, PXDoc table, filename): 226 | """ 227 | Create a new BlobFile instance, associated to the given external file. 228 | """ 229 | 230 | self.filename = filename 231 | self.blob = PX_new_blob(table.doc) 232 | self.isopen = 0 233 | 234 | def open(self): 235 | """ 236 | Actually open the external blob file. 237 | """ 238 | 239 | if PX_open_blob_file(self.blob, self.filename)<0: 240 | raise Exception("Couldn't open blob `%s`" % self.filename) 241 | self.isopen = 1 242 | 243 | def close(self): 244 | """ 245 | Close the external blob file, if needed. 246 | """ 247 | 248 | if self.isopen: 249 | PX_close_blob(self.blob) 250 | self.isopen = 0 251 | 252 | def __dealloc__(self): 253 | """ 254 | Close the external blob file 255 | """ 256 | 257 | self.close() 258 | 259 | cdef class PrimaryIndex(PXDoc): 260 | """ 261 | The primary index file. 262 | """ 263 | 264 | def open(self): 265 | """ 266 | Open the primary index file. 267 | """ 268 | 269 | PXDoc.open(self) 270 | if PX_read_primary_index(self.doc)<0: 271 | raise Exception("Couldn't read primary index `%s`" % self.filename) 272 | 273 | 274 | cdef class Record 275 | 276 | 277 | cdef class Table(PXDoc): 278 | """ 279 | A `Table` represent a Paradox table, with primary index and blob file. 280 | 281 | An instance has notion about the current record number, and 282 | keeps a copy of the values associated to each field. 283 | """ 284 | 285 | cdef readonly Record record 286 | cdef int current_recno 287 | cdef BlobFile blob 288 | cdef PrimaryIndex primary_index 289 | 290 | cdef fields 291 | 292 | def create(self, *fields): 293 | self.fields = fields 294 | n = len(fields) 295 | cdef pxfield_t *f = (self.doc.malloc(self.doc, 296 | n * sizeof(pxfield_t), 297 | "Memory for fields")) 298 | for i from 0 <= i < n: 299 | f[i].px_fname = PX_strdup(self.doc, fields[i].fname) 300 | f[i].px_flen = fields[i].flen 301 | f[i].px_ftype = fields[i].ftype 302 | f[i].px_fdc = 0 303 | 304 | if PX_create_file(self.doc, f, n, self.filename, pxfFileTypIndexDB) < 0: 305 | raise Exception("Couldn't open '%s'" % self.filename) 306 | self.isopen = 1 307 | self.current_recno = -1 308 | 309 | def open(self): 310 | """ 311 | Open the data file and associate a Record instance. 312 | """ 313 | 314 | PXDoc.open(self) 315 | self.record = Record(self) 316 | self.current_recno = -1 317 | self.primary_index = None 318 | 319 | def close(self): 320 | """ 321 | Close the eventual primary index or blob file, then the data file. 322 | """ 323 | 324 | if self.primary_index: 325 | self.primary_index.close() 326 | if self.blob: 327 | self.blob.close() 328 | 329 | PXDoc.close(self) 330 | 331 | def getCodePage(self): 332 | """ 333 | Return the code page of the underlying Paradox table. 334 | """ 335 | 336 | return "cp%d" % self.doc.px_head.px_doscodepage 337 | 338 | def setPrimaryIndex(self, indexname): 339 | """ 340 | Set the primary index of the table. 341 | """ 342 | 343 | self.primary_index = PrimaryIndex(indexname) 344 | self.primary_index.open() 345 | if PX_add_primary_index(self.doc, self.primary_index.doc)<0: 346 | raise Exception("Couldn't add primary index `%s`" % indexname) 347 | 348 | def setBlobFile(self, blobfilename): 349 | """ 350 | Set and open the external blob file. 351 | """ 352 | self.blob = BlobFile(self, blobfilename) 353 | self.blob.open() 354 | 355 | def getFieldsCount(self): 356 | """ 357 | Get number of fields in the table. 358 | """ 359 | 360 | return self.record.getFieldsCount() 361 | 362 | def readRecord(self, recno=None): 363 | """ 364 | Read the data of the next/some specific `recno` record. 365 | 366 | Return False if at EOF or `recno` is beyond the last record, 367 | True otherwise. This makes this method suitable to be called 368 | in a while loop in this way:: 369 | 370 | record = t.record 371 | while t.readRecord(): 372 | for i in range(record.getFieldsCount()): 373 | f = record.fields[i] 374 | value = f.getValue() 375 | print "%s: %s" % (f.fname, value) 376 | """ 377 | 378 | if not recno: 379 | recno = self.current_recno+1 380 | else: 381 | self.current_recno = recno 382 | 383 | if recno>=self.doc.px_head.px_numrecords: 384 | return False 385 | 386 | self.current_recno = recno 387 | 388 | return self.record.read(recno) 389 | 390 | def append(self, values): 391 | cdef char *b 392 | l = len(self.fields) 393 | n = sum([ f.flen for f in self.fields ]) 394 | bufsize = n * sizeof(char) 395 | cdef char *buffer = (self.doc.malloc(self.doc, 396 | bufsize, 397 | "Memory for appended record")) 398 | memset(buffer, 0, bufsize) 399 | o = 0 400 | fs = {} 401 | for i from 0 <= i < l: 402 | f = self.fields[i] 403 | v = values.get(f.fname, None) 404 | l = f.flen 405 | if v == None: 406 | l = 0 407 | if f.ftype == pxfAlpha: 408 | s = unicode(str(v or '').decode('utf-8')) 409 | s = s.encode(self.getCodePage()) 410 | b = (self.doc.malloc(self.doc, f.flen, "Memory for alpha field")) 411 | memcpy(b, s, max(f.flen, len(s))) 412 | PX_put_data_alpha(self.doc, &buffer[o], f.flen, b) 413 | self.doc.free(self.doc, b) 414 | elif f.ftype == pxfLong: 415 | PX_put_data_long(self.doc, &buffer[o], l, int(v or 0)) 416 | elif f.ftype == pxfNumber: 417 | PX_put_data_double(self.doc, &buffer[o], l, float(v or 0.0)) 418 | else: 419 | raise Exception("unknown type") 420 | o += f.flen 421 | 422 | 423 | if PX_put_record(self.doc, buffer) == -1: 424 | raise Exception("unable to put record") 425 | 426 | self.doc.free(self.doc, buffer) 427 | 428 | self.current_recno = self.current_recno + 1 429 | 430 | cdef class ParadoxField: 431 | cdef readonly fname 432 | cdef readonly ftype 433 | cdef readonly flen 434 | 435 | def __cinit__(self, *args): 436 | #print 'ParadoxField cinit', args 437 | pass 438 | 439 | def _init_fields(self, fname, int ftype, int flen): 440 | self.fname = fname 441 | self.ftype = ftype 442 | self.flen = flen 443 | 444 | def __init__(self, fname, int ftype, int flen): 445 | self._init_fields(fname, ftype, flen) 446 | 447 | def default_field_length(int ftype, len = 10): 448 | if ftype == pxfLong: 449 | return 4 450 | elif ftype == pxfAlpha: 451 | return len 452 | elif ftype == pxfNumber: 453 | return 8 454 | else: 455 | return 0 456 | 457 | def type_to_field_type(type ftype): 458 | if ftype == int: 459 | return pxfLong 460 | elif ftype == str: 461 | return pxfAlpha 462 | elif ftype == float: 463 | return pxfNumber 464 | else: 465 | raise Exception("unsupported field type %s" % ftype) 466 | 467 | cdef class Field(ParadoxField): 468 | def __init__(self, fname, type t, int flen = 0): 469 | ft = type_to_field_type(t) 470 | fl = default_field_length(ft, flen) 471 | ParadoxField.__init__(self, fname, ft, fl) 472 | 473 | cdef class RecordField(ParadoxField): 474 | """ 475 | Represent a single field of a Record associated to some Table. 476 | """ 477 | 478 | cdef void *data 479 | cdef Record record 480 | 481 | def __init__(self, Record record, int index, int offset): 482 | """ 483 | Create a new instance, associated with the given `record`, 484 | pointing to the index-th field, which data is displaced by 485 | `offset` from the start of the record memory buffer. 486 | """ 487 | 488 | self.record = record 489 | self.data = record.data+offset 490 | ParadoxField.__init__(self, 491 | record.table.doc.px_head.px_fields[index].px_fname, 492 | record.table.doc.px_head.px_fields[index].px_ftype, 493 | record.table.doc.px_head.px_fields[index].px_flen) 494 | 495 | def getValue(self): 496 | """ 497 | Get the field's value. 498 | 499 | Return some Python value representing the current value of the field. 500 | """ 501 | 502 | cdef double value_double 503 | cdef long value_long 504 | cdef char value_char 505 | cdef short value_short 506 | cdef int year, month, day 507 | cdef char *blobdata 508 | cdef int size 509 | cdef int mod_nr 510 | 511 | if self.ftype == pxfAlpha: 512 | codepage = self.record.table.getCodePage() 513 | size = strnlen( self.data, self.flen) 514 | 515 | if size==0: 516 | return None 517 | else: 518 | py_string = PyString_FromStringAndSize( self.data, size); 519 | if not py_string: 520 | raise Exception("Cannot get value from string %s" % self.fname) 521 | return PyString_AsDecodedObject(py_string, codepage, "replace") 522 | 523 | elif self.ftype == pxfDate: 524 | if PX_get_data_long(self.record.table.doc, 525 | self.data, self.flen, &value_long)<0: 526 | raise Exception("Cannot extract long field '%s'" % self.fname) 527 | if value_long: 528 | PX_SdnToGregorian(value_long+1721425, 529 | &year, &month, &day) 530 | return datetime.date(year, month, day) 531 | else: 532 | return None 533 | 534 | elif self.ftype == pxfShort: 535 | ret = PX_get_data_short(self.record.table.doc, 536 | self.data, self.flen, &value_short) 537 | if ret < 0: 538 | raise Exception("Cannot extract short field '%s'" % self.fname) 539 | 540 | if ret == 0: 541 | return None 542 | 543 | return value_short 544 | 545 | elif self.ftype == pxfLong or self.ftype == pxfAutoInc: 546 | ret = PX_get_data_long(self.record.table.doc, 547 | self.data, self.flen, &value_long) 548 | if ret < 0: 549 | raise Exception("Cannot extract long field '%s'" % self.fname) 550 | if ret == 0: 551 | return None 552 | 553 | return value_long 554 | 555 | elif self.ftype == pxfCurrency or self.ftype == pxfNumber: 556 | ret = PX_get_data_double(self.record.table.doc, 557 | self.data, self.flen, &value_double) 558 | if ret < 0: 559 | raise Exception("Cannot extract double field '%s'" % self.fname) 560 | if ret == 0: 561 | return None 562 | return value_double 563 | 564 | elif self.ftype == pxfLogical: 565 | ret = PX_get_data_byte(self.record.table.doc, 566 | self.data, self.flen, &value_char) 567 | if ret < 0: 568 | raise Exception("Cannot extract double field '%s'" % self.fname) 569 | if ret == 0: 570 | return None 571 | 572 | if value_char: 573 | return True 574 | else: 575 | return False 576 | 577 | elif self.ftype in [pxfMemoBLOb, pxfFmtMemoBLOb]: 578 | 579 | if not self.record.table.blob: 580 | return "NO BLOB FILE" 581 | 582 | blobdata = PX_read_blobdata(self.record.table.blob.blob, 583 | self.data, self.flen, 584 | &mod_nr, &size) 585 | if blobdata and size>0: 586 | codepage = self.record.table.getCodePage() 587 | py_string = PyString_FromStringAndSize( blobdata, size); 588 | if not py_string: 589 | raise Exception("Cannot get value from string %s" % self.fname) 590 | return PyString_AsDecodedObject(py_string, codepage, "replace") 591 | 592 | elif self.ftype in [pxfBLOb, pxfGraphic]: 593 | if not self.record.table.blob: 594 | return "NO BLOB FILE" 595 | 596 | blobdata = PX_read_blobdata(self.record.table.blob.blob, 597 | self.data, self.flen, 598 | &mod_nr, &size) 599 | if blobdata and size>0: 600 | return PyString_FromStringAndSize(blobdata, size) 601 | 602 | elif self.ftype == pxfOLE: 603 | pass 604 | elif self.ftype == pxfTime: 605 | if PX_get_data_long(self.record.table.doc, 606 | self.data, self.flen, &value_long)<0: 607 | raise Exception("Cannot extract long field '%s'" % self.fname) 608 | if value_long: 609 | return datetime.time(value_long/3600000, 610 | value_long/60000%60, 611 | value_long%60000/1000.0) 612 | else: 613 | return None 614 | 615 | elif self.ftype == pxfTimestamp: 616 | pass 617 | elif self.ftype == pxfBCD: 618 | pass 619 | elif self.ftype == pxfBytes: 620 | pass 621 | elif self.ftype == pxfNumTypes: 622 | pass 623 | 624 | 625 | cdef class Record: 626 | """ 627 | An instance of this class wraps the memory buffer associated to a 628 | single record of a given table. 629 | """ 630 | 631 | cdef void *data 632 | cdef Table table 633 | cdef public fields 634 | 635 | def __init__(self, Table table): 636 | """ 637 | Create a Record instance, allocating the memory buffer and 638 | building the list of the Field instances. 639 | """ 640 | 641 | cdef int offset 642 | 643 | self.data = table.doc.malloc(table.doc, 644 | table.doc.px_head.px_recordsize, 645 | "Memory for record") 646 | self.table = table 647 | self.fields = [] 648 | offset = 0 649 | for i in range(self.getFieldsCount()): 650 | field = RecordField(self, i, offset) 651 | self.fields.append(field) 652 | offset = offset + table.doc.px_head.px_fields[i].px_flen 653 | 654 | def getFieldsCount(self): 655 | """ 656 | Get number of fields in the record. 657 | """ 658 | return self.table.doc.px_head.px_numfields 659 | 660 | def read(self, recno): 661 | """ 662 | Read the data associated to the record numbered `recno`. 663 | """ 664 | 665 | if PX_get_record(self.table.doc, recno, self.data) == NULL: 666 | raise Exception("Couldn't get record %d from '%s'" % (recno, 667 | self.table.filename)) 668 | return True 669 | 670 | --------------------------------------------------------------------------------