-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathOPK.py
139 lines (111 loc) · 3.23 KB
/
OPK.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
from sys import argv
from cStringIO import StringIO
from ctypes import POINTER, Structure, cdll, c_char_p, c_void_p, \
c_int, c_uint, byref, string_at
def _checkOpen(result, func, arguments):
if result:
return result
else:
raise IOError("Failed to open OPK file: '%s'" % arguments[0])
def _checkRead(result, func, arguments):
if result >= 0:
return result
else:
raise SyntaxError("Error occured while reading meta-data")
def _checkExtract(result, func, arguments):
if result == 0:
return result
else:
raise IOError("Unable to extract file from OPK")
def _init():
class _OPK(Structure):
pass
OpkPtr = POINTER(_OPK)
lib = cdll.LoadLibrary('libopk.so.1')
opk_open = lib.opk_open
opk_open.restype = OpkPtr
opk_open.archtypes = (c_char_p, )
opk_open.errcheck = _checkOpen
global _opk_open
_opk_open = opk_open
opk_close = lib.opk_close
opk_close.restype = None
opk_close.archtypes = (OpkPtr, )
global _opk_close
_opk_close = opk_close
opk_open_metadata = lib.opk_open_metadata
opk_open_metadata.restype = c_int
opk_open_metadata.archtypes = (OpkPtr, c_char_p, )
opk_open_metadata.errcheck = _checkRead
global _opk_open_metadata
_opk_open_metadata = opk_open_metadata
opk_read_pair = lib.opk_read_pair
opk_read_pair.restype = c_int
opk_read_pair.archtypes = (OpkPtr, c_char_p, c_uint, c_char_p, c_uint)
global _opk_read_pair
_opk_read_pair = opk_read_pair
opk_extract_file = lib.opk_extract_file
opk_extract_file.restype = c_int
opk_extract_file.archtypes = (OpkPtr, c_char_p, c_void_p, c_uint)
opk_extract_file.errcheck = _checkExtract
global _opk_extract_file
_opk_extract_file = opk_extract_file
_init()
class OPK(object):
def __init__(self, path):
self._opk = _opk_open(path)
def __del__(self):
_opk_close(self._opk)
def open_metadata(self):
name = c_char_p()
ret = _opk_open_metadata(self._opk, byref(name))
if ret == 1:
return name.value
def read_pair(self):
key = c_char_p()
key_len = c_uint()
val = c_char_p()
val_len = c_uint()
ret = _opk_read_pair(self._opk, \
byref(key), byref(key_len), \
byref(val), byref(val_len))
if ret == 1:
return (key.value[:key_len.value], val.value[:val_len.value])
return (None, None)
def extract_file(self, filename):
ptr = c_char_p()
size = c_uint()
_opk_extract_file(self._opk, filename, byref(ptr), byref(size))
output = StringIO()
output.write(string_at(ptr, size.value))
return output
def read_metadata(filename):
opk = OPK(filename)
opk_dict = {}
while True:
mdata = opk.open_metadata()
if not mdata:
break
mdata_dict = {}
while True:
key, value = opk.read_pair()
if not key:
break
mdata_dict[key] = value
# We try to be future-proof here; libopk will maybe include support for
# other sections than the regular [Desktop Entry], so for now we
# register the meta-data in another dictionnary with only one key
# named after the 'Desktop Entry' section.
opk_dict[mdata] = {'Desktop Entry': mdata_dict }
return opk_dict
def extract_file(opk_filename, filename):
return OPK(opk_filename).extract_file(filename)
def main():
if len(argv) < 2:
print "Usage: opk.py app1.opk [app2.opk ...]"
return
for arg in argv[1:]:
print read_metadata(arg)
print ""
if __name__ == '__main__':
main()