Created
June 28, 2013 16:41
-
-
Save simon816/5886103 to your computer and use it in GitHub Desktop.
A class which will hopefully be able to decode and extract data from the OperaDataStoreV2.dat file which is Opera Moblie's storage.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import struct | |
import time | |
DATA_STORE_HEADER='P\x00\x00\x10\xe4\x00\x00\x10\x01\x00\x00\x00\xbe\r9G' | |
class OperaDataStore: | |
def __init__(self, filearg): | |
if isinstance(filearg,file): | |
self.file=filearg | |
else: | |
self.file=open(filearg) | |
self.file.seek(0) | |
head=self.file.read(len(DATA_STORE_HEADER)) | |
if head!=DATA_STORE_HEADER: | |
self.file.close() | |
raise TypeError('File is not an Opera Data Store') | |
def readInt(self): | |
return struct.unpack('>i',self.file.read(4))[0] | |
def readSpecialInt(self,len): | |
chars=self.file.read(len) | |
return int(''.join([('%2s'%hex(ord(c))[2:]).replace(' ','0') for c in chars]),16) | |
def readShort(self): | |
return struct.unpack('>h',self.file.read(2))[0] | |
def readFully(self): | |
self.id=self.file.read(14) | |
self.file.read(160) | |
key=self.file.read(4) | |
if key=='\x21\x5a\x1d\x1a': | |
self.readSearchEngines() | |
self.readInt()==0 | |
self.readInt()==4 | |
self.readInt()==0 | |
self.readInt()==6045784 | |
if self.readInt()==6: | |
self.readHistory() | |
key=self.file.read(4) | |
if key=='\x17\x40\x13\x00': | |
self.readUnknown1() | |
key=self.file.read(4) | |
if key=='\x13\x40\x0f\x00': | |
self.readVersion() | |
key=self.file.read(4) | |
if key=='\x05\x40\x01\x00': | |
self.readUnknown2() | |
key=self.file.read(4) | |
if key=='\x10\x40\x0c\x00': | |
self.readUnknown3() | |
key=self.file.read(4) | |
if key=='\x00\x00\x00\x13': | |
self.readSpeedDial() | |
key=self.file.read(4) | |
if key=='\x00\x9e\x40\x9a': | |
self.readBookmarks() | |
self.readUnknown4() | |
key=self.readSpecialInt(3) | |
if key == 5: | |
self.readSavedPages() | |
self.file.read(117) | |
key=self.file.read(4) | |
if key=='\x43\x54\x3f\x14': | |
self.readConstantUnknown2() | |
key=self.file.read(4) | |
if key=='\x80\x01\x00\x00': | |
self.readUnknown5() | |
self.readSettings() | |
self.readStrangeCounter() | |
self.flush() | |
def readSearchEngines(self): | |
self.searchengines=[] | |
if not self.file.read(4)=='\x00\x00\x00\x0c': | |
print 'test1 @ readSearchEngines' | |
return | |
total=self.readInt() | |
self.readInt()==3 | |
hashlen=self.readSpecialInt(3) | |
self.searchenginehash=self.file.read(hashlen) | |
for i in range(total): | |
se={} | |
namelen=self.readShort() | |
se['name']=self.file.read(namelen) | |
urllen=self.readShort() | |
se['url']=self.file.read(urllen) | |
encodinglen=self.readShort() | |
se['encoding']=self.file.read(encodinglen) | |
iconlen=self.readShort() | |
se['iconbytes']=self.file.read(iconlen) | |
mode=self.file.read(4) | |
self.readInt() | |
if mode=='\x01\x00\x01\x00': | |
#nothing else | |
self.file.read(10) | |
elif mode=='\x01\x01\x00\x00': | |
urllen=self.readSpecialInt(3) | |
se['autocompleteurl']=self.file.read(urllen) | |
self.file.read(7) | |
elif mode=='\x00\x00\x00\x01': | |
self.file.read(7) | |
ln=self.readSpecialInt(3) | |
self.file.read(ln) | |
else: | |
self.file.read(10) | |
self.searchengines.append(se) | |
def readHistory(self): | |
self.history=[] | |
totalhistory=self.readShort() | |
for i in range(totalhistory): | |
hist={} | |
surllen=self.readShort() | |
hist['shorturl']=self.file.read(surllen) | |
urllen=self.readShort() | |
hist['url']=self.file.read(urllen) | |
namelen=self.readShort() | |
hist['name']=self.file.read(namelen) | |
hist['time']=time.localtime(self.readInt()) | |
something=self.readInt() | |
iconlen=self.readInt() | |
hist['iconbytes']=self.file.read(iconlen) | |
self.history.append(hist) | |
def readUnknown1(self): | |
self.file.read(4) | |
len1=self.readShort() | |
self.file.read(len1)=='com' | |
self.file.read(12) | |
def readVersion(self): | |
verlen=self.readInt() | |
self.version=self.file.read(verlen) | |
self.readInt()==self.readInt()==0 | |
def readUnknown2(self): | |
#appears directly after readVersion on demo file | |
self.file.read(7) | |
self.readVersion() | |
def readUnknown3(self): | |
self.file.read(8857) | |
def readSpeedDial(self): | |
self.speeddial=[] | |
total=self.readShort() | |
for i in range(total): | |
sd={} | |
self.readInt() | |
namelen=self.readSpecialInt(3) | |
sd['name']=self.file.read(namelen) | |
urllen=self.readShort() | |
sd['url']=self.file.read(urllen) | |
self.file.read(7) | |
hashlen=self.readShort() | |
sd['hash']=self.file.read(hashlen) | |
self.file.read(10) | |
self.speeddial.append(sd) | |
self.file.read(8) | |
def readBookmarks(self): | |
self.bookmarks=[] | |
self.readInt()==48 | |
self.readInt()==3 | |
self.file.read(7) | |
total=self.readInt() | |
for i in range(total): | |
bm={} | |
self.file.read(5) | |
hash1len=self.readShort() | |
bm['hash1']=self.file.read(hash1len) | |
titlelen=self.readShort() | |
bm['title']=self.file.read(titlelen) | |
urllen=self.readSpecialInt(3) | |
bm['url']=self.file.read(urllen) | |
iconlen=self.readShort() | |
bm['iconbytes']=self.file.read(iconlen) | |
self.readShort() | |
hash2len=self.readShort() | |
bm['hash2']=self.file.read(hash2len) | |
self.bookmarks.append(bm) | |
def readUnknown4(self): | |
self.readInt()==0 | |
self.readInt()==9 | |
self.file.read(105) | |
self.file.read(self.readShort()) | |
self.file.read(168) | |
self.file.read(19) | |
self.readConstantUnknown1() | |
self.file.read(3) | |
self.file.read(struct.unpack('<h',self.file.read(2))[0]) | |
self.file.read(6) | |
def readConstantUnknown1(self): | |
#this always is at position 80f7 | |
self.file.read(2270) | |
#and ends with 0xff at position 89d5 | |
def readSavedPages(self): | |
self.savedpages=[] | |
total=self.readInt() | |
for i in range(total): | |
sp={} | |
self.readInt()==1 | |
titlelen=self.readShort() | |
sp['title']=self.file.read(titlelen) | |
urllen=self.readShort() | |
sp['url']=self.file.read(urllen) | |
sp['filename']=str(self.readInt())+'.mhtml' | |
iconlen=self.readInt() | |
sp['iconbytes']=self.file.read(iconlen) | |
self.savedpages.append(sp) | |
def readConstantUnknown2(self): | |
self.file.read(5186) | |
def readUnknown5(self): | |
self.file.read(170) | |
png=self.file.read(self.readInt()) | |
self.file.read(203) | |
self.file.read(struct.unpack('<h',self.file.read(2))[0]) | |
self.file.read(6) | |
def readSettings(self): | |
self.settings=[] | |
totalkeys=self.readSpecialInt(1) | |
for i in range(totalkeys): | |
a_number=self.readInt() | |
l=self.readInt() | |
self.file.read(2) | |
key=self.file.read(l*2).replace('\x00','') | |
value=self.readShort() | |
self.settings.append((a_number,key,value)) | |
def readStrangeCounter(self): | |
l=self.readInt() | |
s=self.file.read(l) | |
numbers=[] | |
for ch in range(1,(l/4)): | |
numbers.append(struct.unpack('>i',s[(ch*4)-1:(ch*4+4)-1])[0]) | |
#print numbers | |
def flush(self): | |
#finishes reading the file and dumps any remaining bytes to 'file_end_data' | |
self.file_end_data=self.file.read() | |
self.filesize=self.file.tell() | |
#close file- no more reading allowed | |
self.file.close() | |
if __name__=='__main__': | |
ods=OperaDataStore('e:\\O\\OperaDataStoreV2.demo'); | |
ods.readFully(); | |
print repr(ods.id) | |
for attr in ['searchengines','history']: | |
print attr,'=',[(getattr(ods,attr).index(s),s['name']) for s in getattr(ods,attr)] | |
#*.dat2 @ln 89454 | |
print ods.version | |
print ods.speeddial | |
print ods.bookmarks | |
print ods.savedpages | |
print ods.settings |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment