File: pdbfile.py

package info (click to toggle)
pyrite 0.9.3
  • links: PTS
  • area: main
  • in suites: potato
  • size: 1,504 kB
  • ctags: 1,924
  • sloc: python: 6,064; ansic: 5,094; makefile: 275; sh: 172
file content (177 lines) | stat: -rw-r--r-- 5,395 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#
#  $Id: pdbfile.py,v 1.7 1999/08/09 21:59:13 rob Exp $
#
#  Copyright 1998-1999 Rob Tillotson <robt@debian.org>
#  All Rights Reserved
#
#  Permission to use, copy, modify, and distribute this software and
#  its documentation for any purpose and without fee or royalty is
#  hereby granted, provided that the above copyright notice appear in
#  all copies and that both the copyright notice and this permission
#  notice appear in supporting documentation or portions thereof,
#  including modifications, that you you make.
#
#  THE AUTHOR ROB TILLOTSON DISCLAIMS ALL WARRANTIES WITH REGARD TO
#  THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
#  AND FITNESS.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
#  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
#  RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
#  CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
#  CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE!
#
"""PDB file utilities.

  This module contains various utility functions which may be useful
  to programs -- installers, conduits, etc. -- that deal with PalmOS
  databases on the desktop.
"""

__version__ = '$Id: pdbfile.py,v 1.7 1999/08/09 21:59:13 rob Exp $'

__copyright__ = 'Copyright 1998-1999 Rob Tillotson <robt@debian.org>'


import Pyrite

import sys, os, stat, struct

PI_HDR_SIZE = 78
PILOT_TIME_DELTA = 2082844800

dlpDBFlagResource = 0x0001
dlpDBFlagReadOnly = 0x0002
dlpDBFlagAppInfoDirty = 0x0004
dlpDBFlagBackup = 0x0008
dlpDBFlagOpen = 0x8000
# 2.x
dlpDBFlagNewer = 0x0010
dlpDBFlagReset = 0x0020
#
dlpDBMiscFlagExcludeFromSync = 0x80

def flags_to_info(flags):
    """Convert a numeric flag word to a dictionary.
    The result is suitable for merging into an info structure
    with 'update'.
    """
    i = {'flagReset': flags & dlpDBFlagReset,
	 'flagResource': flags & dlpDBFlagResource,
	 'flagNewer': flags & dlpDBFlagNewer,
	 'flagExcludeFromSync': flags & dlpDBMiscFlagExcludeFromSync,
	 'flagAppInfoDirty': flags & dlpDBFlagAppInfoDirty,
	 'flagReadOnly': flags & dlpDBFlagReadOnly,
	 'flagBackup': flags & dlpDBFlagBackup,
	 'flagOpen': flags & dlpDBFlagOpen,
	 }
    return i

def info_to_flags(i):
    """Extract a numeric flag word from an info structure.
    """
    flags = 0
    if i.get('flagReset'): flags = flags | dlpDBFlagReset
    if i.get('flagResource'): flags = flags | dlpDBFlagResource
    if i.get('flagNewer'): flags = flags | dlpDBFlagNewer
    if i.get('flagExcludeFromSync'): flags = flags | dlpDBMiscFlagExcludeFromSync
    if i.get('flagAppInfoDirty'): flags = flags | dlpDBFlagAppInfoDirty
    if i.get('flagBackup'): flags = flags | dlpDBFlagBackup
    if i.get('flagOpen'): flags = flags | dlpDBFlagOpen
    return flags

def null_terminated(s):
    for x in range(0, len(s)):
	if s[x] == '\000': return s[:x]
    return s

def info(name):
    """Read the header of a PalmOS database file.  Although there is
    no way to conclusively determine that a file contains a valid
    database, this function does a few simple checks and returns None
    if the file is invalid.  Pilot-link also does this on open, but
    since it prints error messages to stderr it is inappropriate to
    use it to test a bunch of files in a directory."""
    
    f = open(name, 'rb')
    hstr = f.read(PI_HDR_SIZE)
    if not hstr or len(hstr) < PI_HDR_SIZE: return None

    (name, flags, ver, ctime, mtime, btime, mnum, appinfo, sortinfo,
     type, creator, uid, nextrec, numrec) \
     = struct.unpack('>32shhLLLlll4s4sllh', hstr)

    # "extended format not supported"
    if nextrec: return None

    # "bad header"
    if appinfo < 0 or sortinfo < 0 or numrec < 0: return None

    i = {'name': null_terminated(name),
	 'type': type,
	 'creator': creator,
	 'createDate': ctime - PILOT_TIME_DELTA,
	 'modifyDate': mtime - PILOT_TIME_DELTA,
	 'backupDate': btime - PILOT_TIME_DELTA,
	 'modnum': 3,
	 'version': ver,
	 'flagReset': flags & dlpDBFlagReset,
	 'flagResource': flags & dlpDBFlagResource,
	 'flagNewer': flags & dlpDBFlagNewer,
	 'flagExcludeFromSync': flags & dlpDBMiscFlagExcludeFromSync,
	 'flagAppInfoDirty': flags & dlpDBFlagAppInfoDirty,
	 'flagReadOnly': flags & dlpDBFlagReadOnly,
	 'flagBackup': flags & dlpDBFlagBackup,
	 'flagOpen': flags & dlpDBFlagOpen,
	 'more': 0,
	 'index': 0
	 }

    return i

    
def x_info(name):
    """Return the info structure of a PalmOS database file."""

    f = Pyrite.openFile(name, typemapper=None)
    return f.info

def listdir(path):
    """Scan the specified path for PalmOS database files and return
    a list of tuples of (name, info) for each database found.
    This function may be expanded in the future to handle zipfiles,
    gzipped databases, etc."""

    d = os.listdir(path)
    l = []
    
    for f in d:
	fn = os.path.join(path, f)

	# any exception at all means that the file isn't worth reporting
	try:
	    st = os.stat(fn)

	    if stat.S_ISREG(st[stat.ST_MODE]):
		i = info(fn)
		if i:
		    l.append( (f, i) )
	except:
	    pass

    return l

def listsubdirs(path):
    """List all subdirectories of the current directory."""
    # doesn't really belong here
    d = os.listdir(path)
    l = []

    for f in d:
	fn = os.path.join(path, f)
	try:
	    st = os.stat(fn)
	    if stat.S_ISDIR(st[stat.ST_MODE]): l.append(f)
	except:
	    pass
    return l