PageRenderTime 483ms CodeModel.GetById 37ms RepoModel.GetById 1ms app.codeStats 0ms

/palm.py

https://bitbucket.org/micseydel/palm-database-reader
Python | 125 lines | 105 code | 12 blank | 8 comment | 9 complexity | 993494a7ad42d61d428a225eb782dacf MD5 | raw file
  1. #!/usr/bin/env python
  2. import sys
  3. import struct
  4. import ctypes as c
  5. PALM_EPOCHE_CONV = 2082844800
  6. class PalmDB(object):
  7. "An entire Palm Database; a file"
  8. def __init__(self, filename):
  9. self.filename = filename
  10. with open(filename) as f:
  11. self.header = PDBHeader(f.read(0x4e))
  12. self.record_list = [PDBRecordHeader(f.read(8))
  13. for x in xrange(self.header.num_records)]
  14. f.read(2) #no idea what this is
  15. self.records = self._get_records(f)
  16. def _get_records(self, file_object):
  17. return [PDBRecord(file_object, record.offset)
  18. for record in self.record_list]
  19. class PDBHeader(c.Structure):
  20. "The header for a palm database, the 78 bytes"
  21. _fields_ = [
  22. ("name", c.c_char_p),
  23. ("file_attys", c.c_ushort),
  24. ("version", c.c_ushort),
  25. ("creation_time", c.c_uint),
  26. ("mod_time", c.c_uint),
  27. ("backup_time", c.c_uint),
  28. ("mod_num", c.c_uint),
  29. ("app_info", c.c_uint),
  30. ("sort_info", c.c_uint),
  31. ("type", c.c_uint),
  32. ("creator", c.c_uint),
  33. ("unique_id", c.c_uint),
  34. ("next_record_list", c.c_uint),
  35. ("num_records", c.c_ushort)
  36. ]
  37. _format = struct.Struct(">32sHHIIIIIIIIIIH")
  38. def __init__(self, packed_string):
  39. super(type(self), self).__init__(*self._format.unpack(packed_string))
  40. #let us use regular time
  41. self.creation_time -= PALM_EPOCHE_CONV
  42. self.mod_num -= PALM_EPOCHE_CONV
  43. self.backup_time -= PALM_EPOCHE_CONV
  44. class PDBRecordHeader(c.Structure):
  45. "The offset seems to be the only thing of importance here"
  46. _fields_ = [
  47. ("offset", c.c_uint),
  48. ("attys", c.c_char), #always seems to be @
  49. ("unique_id", c.c_char_p) #documentation says this should always be 0
  50. ]
  51. _format = struct.Struct(">Ic3s")
  52. def __init__(self, packed_string):
  53. super(type(self), self).__init__(*self._format.unpack(packed_string))
  54. def __repr__(self):
  55. return "PDBRecordHeader(offset=0x{:X}, attys={})".format(
  56. self.offset, self.attys)
  57. # this may vary wildly!
  58. class PDBRecord(object):
  59. "TBI"
  60. format = struct.Struct(">I")
  61. def __init__(self, f, offset):
  62. f.seek(offset)
  63. f.read(10)
  64. print "0x{:X}".format(offset)
  65. if f.read(1) == "@": # received
  66. #print "received? 1"
  67. f.read(23)
  68. phone_number = get_c_string(f)
  69. name = get_c_string(f)
  70. f.read(3)
  71. t1 = f.read(4)
  72. f.read(2)
  73. t2 = f.read(4)
  74. f.read(2)
  75. t3 = f.read(4)
  76. else: # sent
  77. if f.read(1) == "\x02": # sent
  78. #print "sent? 01"
  79. f.read(23)
  80. sent_time = f.read(4)
  81. f.read(18)
  82. received_time = f.read(4)
  83. f.read(8)
  84. #f.read(57) # there might be something useful here
  85. some_number = ord(f.read(1))
  86. phone_number = get_c_string(f)
  87. name = get_c_string(f)
  88. else: # sent
  89. #print "sent? 11"
  90. f.read(29)
  91. sent_time = f.read(4)
  92. f.read(18)
  93. received_time = f.read(4)
  94. f.read(8)
  95. #f.read(63) # might be something useful
  96. some_number = ord(f.read(1))
  97. phone_number = get_c_string(f)
  98. name = get_c_string(f)
  99. f.read(17) # might be useful here
  100. del f
  101. vars(self).update(locals())
  102. def get_c_string(fileobj):
  103. 'gets a C string from a fileobj, advancing the position'
  104. chars = []
  105. while True: # break when \0 encountered
  106. char = fileobj.read(1)
  107. if char == '\0':
  108. break
  109. chars.append(char)
  110. return "".join(chars)
  111. if __name__ == "__main__":
  112. palm_db = PalmDB(sys.argv[1])