class SQLiteFreelistPage(SQLitePage): def __init__(self, pgn, parent, pageBytes, trunk=0): super(SQLiteFreelistPage, self).__init__(pgn, parent, pageBytes) self.isSubType = None self.isTrunk = trunk self.unallocated = ListRange( ) if trunk: self.type = 'Freelist Trunk' (self.nextTrunkPage, self.leafpageCount) = unpack( '>II', self.stream[0:8] ) self.leafPages = [] offset = 8 for i in range(0, self.leafpageCount): self.leafPages.append( unpack( '>I', self.stream[offset:offset+4] )[0] ) offset += 4 self.unallocated.addRange( [offset, parent.pageSize] ); else: #if isBTreePage( unpack(">B", pageBytes[0:1] )[0]): self.isSubType = SQLiteBTreePage(pgn, self.BTree, pageBytes) self.type = 'Freelist Leaf' self.unallocated.addRange( [1, parent.pageSize] ); def __dump__(self): if self.isTrunk: print "\tNext freelist trunk page:", self.nextTrunkPage print "\tLeaf pages count:", self.leafpageCount print "\tLeaf pages: " + ",".join(["%d" % i for i in self.leafPages ]) if self.isSubType: print "\tSubtype:", self.isSubType.type self.isSubType.__dump__( )
class SQLiteBTreePage(SQLitePage): def __init__(self, pgn, parent, pageBytes, root=0): super(SQLiteBTreePage, self).__init__(pgn, parent, pageBytes) of = 0 self.isFirstPage = root if self.isFirstPage: of += 100 self.Flag = unpack(">B", self.stream[of:of+1])[0] of += 1 if not isBTreePage (self.Flag): return self.FirstBlock = 0 self.numnumCells = 0 self.ContentArea = 0 self.Fragment = 0 self.avgCellSize = 0 self.avgPayloadLen = 0 self.unallocated = ListRange( ) self.Pointer = 0 (self.FirstBlock, self.numCells, self.ContentArea, self.Fragment) = unpack(">3HB", self.stream[of:of+7]) self.maxLocal = self.BTree.maxLocal self.minLocal = self.BTree.minLocal of += 7 if self.Flag & 0x8: self.strType = "Leaf" else: self.strType = "Interior" self.Pointer = unpack(">I", pageBytes[of:of+4])[0] of += 4 if self.Flag & 0x7 == 2: self.strType += " Index"; elif self.Flag & 0x7 == 5: self.strType += " Table"; self.maxLocal = self.BTree.maxLeaf self.minLocal = self.BTree.minLeaf if self.strType != "Unknown": self.type = "BTree" if self.numCells: self.cells = [] self.cellGap.addRange( [self.ContentArea, self.BTree.usableSize] ) avgSize = 0 avgPayload = 0 for i in range(0, self.numCells): co = unpack( ">H", self.stream[of:of+2] )[0] cell = self.readCellHeaderOff(co, i) self.cells.append( cell ) self.cellGap.delRange( [cell['offset'], cell['offset']+cell['cellSize']] ) avgSize += cell['cellSize'] if 'payloadLen' in cell: avgPayload += cell['payloadLen'] of += 2 for r in self.cellGap: self.unallocated.addRange( r ) self.avgCellSize = int(avgSize / self.numCells) self.avgPayloadLen = int(avgPayload / self.numCells) if self.ContentArea == self.BTree.usableSize: self.unallocated.addRange( [of, self.BTree.usableSize] ) else: self.unallocated.addRange( [of, self.ContentArea-1] ) def __dump__(self): if self.isFirstPage: print "\tFirst Page (with file header)" print "\tBTree Page Type", self.Flag, "(" + self.strType + ")" print "\tByte offset into First Freeblock:", self.FirstBlock print "\tNumber of cells:", self.numCells print "\tAvg. cell size:", self.avgCellSize if self.avgPayloadLen: print "\tAvg. payload size:", self.avgPayloadLen print "\tOffset to the first byte of content area:", self.ContentArea print "\tFragment:", self.Fragment if self.numCells: print "\tCell ptrs:", ",".join([ str(i['offset']) for i in self.cells]) if not(self.Flag & 0x8): print "\tThe right-most pointer:", self.Pointer print "\tUnallocated space:", ",".join([str(i) for i in self.unallocated]) print "\tCell gaps:", ",".join([str(i) for i in self.cellGap])