Module sqlite2_file
[hide private]
[frames] | no frames]

Source Code for Module sqlite2_file

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2006 Joe Pham <djpham@bitpim.org> 
  4  ### 
  5  ### This program is free software; you can redistribute it and/or modify 
  6  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
  7  ### 
  8  ### $Id: sqlite2_file.py 3460 2006-07-08 23:55:09Z djpham $ 
  9   
 10  """Handle reading data off an SQLit2 2.x data file""" 
 11   
 12  # System modules 
 13  import struct 
 14   
 15  # SQLite2 constants 
 16  # byte order format 
 17  BO='<'  # default to LE 
 18  signature='** This file contains an SQLite 2.1 database **\x00' 
 19  signature_len=len(signature) 
 20  LE_string='\x28\x75\xe3\xda' 
 21  BE_string='\xda\xe3\x75\x28' 
 22  Page_Length=1024 
 23  Max_Cell_Data_Len=238 
 24   
 25  # SQLite 2.x file handling stuff------------------------------------------------ 
26 -class InvalidFile(Exception):
27 - def __init__(self, bad_sig):
28 global signature 29 Exception.__init__(self, 'Invalid signature: expecting %s, got %s'%(signature, bad_sig)) 30 self.bad_sig=bad_sig
31
32 -class InvalidByteOrder(Exception):
33 - def __init__(self, bad_data):
34 Exception.__init__(self, 'Invalid Byte Order String: %s'%bad_data) 35 self.bad_data=bad_data
36
37 -class BadTable(Exception):
38 - def __init__(self, name):
39 Exception.__init__(self, 'Failed to find table: %s'%name) 40 self.name=name
41
42 -class Cell(object):
43 - def __init__(self, data):
44 global BO, Max_Cell_Data_Len 45 self.prev_key=struct.unpack('%cI'%BO, data[:4])[0] 46 _key_size=struct.unpack('%cH'%BO, data[4:6])[0] 47 self.next_cell=struct.unpack('%cH'%BO, data[6:8])[0] 48 _keysize_hi=struct.unpack('B', data[8])[0] 49 _datasize_hi=struct.unpack('B', data[9])[0] 50 _data_size=struct.unpack('%cH'%BO, data[10:12])[0] 51 _key_size+=_keysize_hi<<16 52 _data_size+=_datasize_hi<<16 53 self.key=struct.unpack('%cI'%BO, data[12:16]) 54 if _data_size>Max_Cell_Data_Len: 55 self.data=data[16:250] 56 self.overflow_page=struct.unpack('%cI'%BO, data[250:254])[0] 57 else: 58 self.data=data[16:16+_data_size] 59 self.overflow_page=0 60 self.data_size=_data_size
61
62 - def get_data(self, page, db_file):
63 global Max_Cell_Data_Len 64 _res=[] 65 if self.prev_key: 66 _res=db_file.get_data(self.prev_key) 67 _my_data=self.data 68 if self.overflow_page: 69 _my_data+=db_file.get_data(self.overflow_page, 70 self.data_size-Max_Cell_Data_Len) 71 _res.append(_my_data) 72 if self.next_cell: 73 _res+=page.get_cell_data(self.next_cell, db_file) 74 return _res
75
76 -class Page(object):
77 - def __init__(self, data):
78 global BO, Page_Length 79 self.prev_key=struct.unpack('%cI'%BO, data[:4])[0] 80 self.cell0=struct.unpack('%cH'%BO, data[4:6])[0] 81 self.freeblock=struct.unpack('%cH'%BO, data[6:8])[0] 82 self.data=data[:Page_Length]
83
84 - def get_cell_data(self, offset, db_file):
85 return Cell(self.data[offset:]).get_data(self, db_file)
86
87 - def get_data(self, db_file, _=None):
88 # return the payload of this page 89 _res=[] 90 if self.prev_key: 91 _res=db_file.get_data(self.prev_key) 92 _res+=self.get_cell_data(self.cell0, db_file) 93 return _res
94
95 -class Page1(object):
96 - def __init__(self, data):
97 global signature, BO, signature_len, LE_string, BE_string 98 _sig=data[:signature_len] 99 if _sig!=signature: 100 raise InvalidFile(_sig) 101 _idx=signature_len 102 _bo_string=data[_idx:_idx+4] 103 if _bo_string==LE_string: 104 BO='<' 105 elif _bo_string==BE_string: 106 BO='>' 107 else: 108 raise InvalidByteOrder(_bo_string) 109 _idx+=4 110 self.first_free_page=struct.unpack('%cI'%BO, data[_idx:_idx+4])[0] 111 _idx+=4 112 self.freelist_pages=struct.unpack('%cI'%BO, data[_idx:_idx+4])[0]
113
114 -class OverflowPage(object):
115 Max_Len=1020
116 - def __init__(self, data):
117 global BO, Page_Length 118 self.next=struct.unpack('%cI'%BO, data[:4])[0] 119 self.data=data[4:Page_Length]
120
121 - def get_data(self, db_file, data_size=None):
122 if data_size: 123 if data_size>self.Max_Len: 124 _res=self.data 125 if self.next: 126 _res+=db_file.get_data(self.next, data_size-self.Max_Len) 127 else: 128 _res=self.data[:data_size] 129 else: 130 _res=self.data 131 return _res
132
133 -class DBFile(object):
134 - def __init__(self, data):
135 self.data=data 136 self.page1=Page1(data) 137 self.tables=self._get_tables()
138
139 - def get_data(self, page_num, data_size=None):
140 global Page_Length 141 if not page_num: 142 return [] 143 # We cheat here a bit since we know the page length is 1k 144 ## _pg_ofs=(page_num-1)*Page_Length 145 _pg_ofs=(page_num-1)<<10 146 if data_size: 147 return OverflowPage(self.data[_pg_ofs:_pg_ofs+Page_Length]).get_data(self, 148 data_size) 149 return Page(self.data[_pg_ofs:_pg_ofs+Page_Length]).get_data(self)
150
151 - def extract_data(self, data, numofcols):
152 # extract one string of data in to a list of numofcols 153 _data_len=len(data) 154 if _data_len<256: 155 _ofs_size=1 156 elif _data_len<65536: 157 _ofs_size=2 158 else: 159 _ofs_size=3 160 _idx=(numofcols+1)*_ofs_size 161 return data[_idx:].split('\x00')[:numofcols]
162
163 - def _get_tables(self):
164 # build a list of tables in this DB 165 _res={} 166 # the master table is stored in page 2, and has 5 fields 167 for _entry in self.get_data(2): 168 _row=self.extract_data(_entry, 5) 169 if _row[0]=='table': 170 _res[_row[1]]={ 'name': _row[1], 171 'page': int(_row[3]), 172 'numofcols': _row[4].count(',')+1 } 173 return _res
174
175 - def get_table_data(self, table_name):
176 # return a list of rows of this table, each row is a list of values 177 if not self.tables.has_key(table_name): 178 raise BadTable(table_name) 179 _page=self.tables[table_name]['page'] 180 _numofcols=self.tables[table_name]['numofcols'] 181 _res=[] 182 for _entry in self.get_data(_page): 183 _res.append(self.extract_data(_entry, _numofcols)) 184 return _res
185