# # PeepDB v 0.1 "Germ" # (c) 2001 Alexey Vyskubov alexey@pepper.spb.ru # some patches by Mark Eichin eichin@thok.org 20031019 # see original at http://linux.piter-press.ru/peepdb/ # import struct def to_byte(s): return struct.unpack('B', s)[0] def from_byte(x): return struct.pack('B', x) def to_word(s): return struct.unpack('>H', s)[0] def from_word(x): return struct.pack('>H', x) def to_dword(s): return struct.unpack('>L', s)[0] def from_dword(x): return struct.pack('>L', x) def assign_byte(dt, b, offset): dt[offset] = b[0] return dt def assign_word(dt, w, offset): dt = dt[:offset]+ w + dt[offset+2:] return dt def assign_dword(dt, dw, offset): dt = assign_word(dt, dw[0:2], offset) dt = assign_word(dt, dw[2:], offset+2) return dt class data_header: "Common header manipulation" def __init__(self, size): self.data = '\0'*size def put_data_byte(self, b, offset): self.data = assign_byte(self.data, from_byte(b), offset) def get_data_byte(self, offset): return to_byte(self.data[offset]) def put_data_bit(self, bit, byte_offset, bit_offset): newbyte = self.get_data_byte(byte_offset) newbit = 2 ** bit_offset if bit == 0: newbyte = newbyte & (255 - newbit) else: newbyte = newbyte | newbit def get_data_bit(self, byte_offset, bit_offset): oldbyte = get_data_byte(byte_offset) oldbit = 2 ** bit_offset return oldbyte & oldbit def put_data_word(self, w, offset): self.data = assign_word(self.data, from_word(w), offset) def get_data_word(self, offset): return to_word(self.data[offset:offset+2]) def put_data_dword(self, dw, offset): self.data = assign_dword(self.data, from_dword(dw), offset) def get_data_dword(self, offset): return to_dword(self.data[offset:offset+4]) def put_data_string(self, str, offset): self.data = self.data[0:offset]+str+self.data[offset+len(str):] def get_data_string(self, len, offset): return self.data[offset:offset+len] class pdb_header(data_header): "PalmOS pdb file header" def set_name(self, nm): k = len(nm) if k > 31: self.put_data_string(nm[0:31]+'\0', 0) else: self.put_data_string(nm+'\0', 0) def set_attributes(self, at): self.put_data_word(at, 32) def get_attributes(self): return self.get_data_word(32) def set_version(self, ver): self.put_data_word(ver, 34) def get_version(self): return self.get_data_word(34) def set_create_time(self, time): self.put_data_dword(time, 36) def get_create_time(self): return self.get_data_dword(36) def set_modify_time(self, time): self.put_data_dword(time, 40) def get_modify_time(self): return self.get_data_dword(40) def set_backup_time(self, time): self.put_data_dword(time, 44) def get_backup_time(self): return self.get_data_dword(44) def set_modification_number(self, num): self.put_data_dword(num, 48) def get_modification_number(self): return self.get_data_dword(48) def set_appInfoID(self, id): self.put_data_dword(num, 52) def get_appInfoID(self): return self.get_data_dword(52) def set_sortInfoID(self, id): self.put_data_dword(num, 56) def get_sortInfoID(self): return self.get_data_dword(56) def set_type(self, type): self.put_data_string(type, 60) def get_type(self): return self.get_data_string(60) def set_creator(self, creat): self.put_data_string(creat, 64) def get_creator(self): return self.get_data_string(64) def set_id_seed(self, seed): self.put_data_dword(seed, 68) def get_id_seed(self): return self.get_data_dword(68) def set_next_record_list(self, list): self.put_data_dword(list, 72) def get_next_record_list(self): return self.get_data_dword(72) def set_number_of_records(self, num): self.put_data_word(num, 76) def get_number_of_records(self): return self.get_data_word(76) def load_from_file(self, filename): f = open(filename, 'r') self.data = f.read(78) f.close() def get_from_pdb(self, pdb): self.data = pdb[0:78] def init(self, nm): data_header.__init__(self, 78) self.set_name(nm) self.set_create_time(1000000) # FIXME self.set_modify_time(1000000) # FIXME self.set_type("NULL") self.set_creator("NULL") def __init__(self, mode, nm): if mode == 'new': self.init(nm) else: if mode == 'load': self.load_from_file(nm) else: if mode == 'get': self.get_from_pdb(nm) # FIXME class record_header(data_header): "PDB's record header" def init(self): data_header.__init__(self, 8) def __init__(self, hdr): if hdr == '': self.init() else: self.data = hdr def set_offset(self, offset): self.put_data_dword(offset, 0) def get_offset(self): return self.get_data_dword(0) def set_delete_bit(self, bit): self.put_data_bit(bit, 4, 7) def set_dirty_bit(self, bit): self.put_data_bit(bit, 4, 6) def set_busy_bit(self, bit): self.put_data_bit(bit, 4, 5) def set_secret_bit(self, bit): self.put_data_bit(bit, 4, 4) def set_category(self, cat): self.put_data_bit((cat & 8)/8, 4, 3) self.put_data_bit((cat & 4)/4, 4, 2) self.put_data_bit((cat & 2)/2, 4, 1) self.put_data_bit(cat & 1, 4, 0) def set_id(self, id): self.put_data_string(id, 5) def get_id(self): return self.get_data_string(3, 5) class palmdb: "PalmOS pdb format" def init(self, nm): self.main_header = pdb_header('new', nm) self.records=[] def __init__(self, mode, nm): if mode == 'new': self.init(nm) else: self.init('noname') if mode == 'load': self.load_from_file(nm) else: if mode == 'get': self.get_from_pdb(nm) # FIXME # FIXME def calculate_offsets(self): ot = 78L + self.main_header.get_number_of_records()*8 # Main PDB's header is 78 bytes # Record's header is 8 bytes for rec in range(self.main_header.get_number_of_records()): self.records[rec][0].set_offset(ot) ot = ot + len(self.records[rec][1]) def create_new_record(self, id, data): self.records.append([]) self.main_header.set_number_of_records(self.main_header.get_number_of_records() + 1) self.records[-1].append(record_header('')) self.records[-1].append(data) self.records[-1][0].set_id(id) self.calculate_offsets() def clean_all_records(self): while (len(self.records)>0): rec = self.records.pop() del rec[0] def get_from_pdb(self, pdb): self.clean_all_records() self.main_header.get_from_pdb(pdb[0:78]) skip = 78 i = self.main_header.get_number_of_records() while i > 0: self.records.append(['', '']) self.records[-1][0] = record_header(pdb[skip:skip+8]) skip = skip + 8 i = i - 1 i = len(self.records) - 1 while (i >= 0): start = int(self.records[i][0].get_offset()) if i == len(self.records) - 1: self.records[i][1] = pdb[start:] else: end = int(self.records[i+1][0].get_offset()) self.records[i][1] = pdb[start:end] i = i - 1 def load_from_file(self, filename): f = open(filename, 'r') pdb = f.read() f.close() self.get_from_pdb(pdb) def save_to_file(self, filename): f = open(filename, 'w') f.write(self.main_header.data) for i in range(self.main_header.get_number_of_records()): f.write(self.records[i][0].data) for i in range(self.main_header.get_number_of_records()): f.write(self.records[i][1]) f.close()