Skip to content

Instantly share code, notes, and snippets.

@simon816
Created June 28, 2013 16:41
Show Gist options
  • Save simon816/5886103 to your computer and use it in GitHub Desktop.
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.
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