Run autopep8
Victor Stinner
7 years ago
68 | 68 | |
69 | 69 | |
70 | 70 | class Grep: |
71 | ||
71 | 72 | def __init__(self): |
72 | 73 | self.pattern = None |
73 | 74 | self.case_sensitive = True |
95 | 96 | |
96 | 97 | |
97 | 98 | class ConsoleGrep(Grep): |
99 | ||
98 | 100 | def __init__(self): |
99 | 101 | Grep.__init__(self) |
100 | 102 | self.term_charset = getTerminalCharset() |
19 | 19 | Compute compression rate, sizes have to be in byte. |
20 | 20 | """ |
21 | 21 | if (not meta.has("file_size") |
22 | or not meta.get("compr_size", 0)): | |
22 | or not meta.get("compr_size", 0)): | |
23 | 23 | return |
24 | 24 | file_size = meta.get("file_size") |
25 | 25 | if not file_size: |
4 | 4 | |
5 | 5 | |
6 | 6 | class ISO9660_Metadata(RootMetadata): |
7 | ||
7 | 8 | def extract(self, iso): |
8 | 9 | desc = iso['volume[0]/content'] |
9 | 10 | self.title = desc['volume_id'].value |
70 | 70 | for entry in ifd.array("entry"): |
71 | 71 | self.processIfdEntry(ifd, entry, attr) |
72 | 72 | if 'BitsPerSample' in attr and 'SamplesPerPixel' in attr: |
73 | self.bits_per_pixel = attr['BitsPerSample'] * attr['SamplesPerPixel'] | |
73 | self.bits_per_pixel = attr[ | |
74 | 'BitsPerSample'] * attr['SamplesPerPixel'] | |
74 | 75 | |
75 | 76 | @fault_tolerant |
76 | 77 | def processIfdEntry(self, ifd, entry, attr): |
38 | 38 | """ |
39 | 39 | # Invalid key? |
40 | 40 | if key not in self.__data: |
41 | raise KeyError("%s has no metadata '%s'" % (self.__class__.__name__, key)) | |
41 | raise KeyError("%s has no metadata '%s'" % | |
42 | (self.__class__.__name__, key)) | |
42 | 43 | |
43 | 44 | # Skip duplicates |
44 | 45 | self.__data[key].add(value) |
76 | 77 | item = self.getItem(key, index) |
77 | 78 | if item is None: |
78 | 79 | if default is None: |
79 | raise ValueError("Metadata has no value '%s' (index %s)" % (key, index)) | |
80 | raise ValueError( | |
81 | "Metadata has no value '%s' (index %s)" % (key, index)) | |
80 | 82 | else: |
81 | 83 | return default |
82 | 84 | return item.value |
181 | 183 | |
182 | 184 | |
183 | 185 | class RootMetadata(Metadata): |
186 | ||
184 | 187 | def __init__(self, quality=QUALITY_NORMAL): |
185 | 188 | Metadata.__init__(self, None, quality) |
186 | 189 | |
239 | 242 | title = key |
240 | 243 | else: |
241 | 244 | title = None |
242 | value = metadata.exportPlaintext(priority, human, line_prefix, title=title) | |
245 | value = metadata.exportPlaintext( | |
246 | priority, human, line_prefix, title=title) | |
243 | 247 | if value: |
244 | 248 | text.extend(value) |
245 | 249 | if len(text): |
61 | 61 | |
62 | 62 | self.compression = format["codec"].display |
63 | 63 | if ("nb_sample/nb_sample" in wav |
64 | and 0 < format["sample_per_sec"].value): | |
65 | self.duration = timedelta(seconds=float(wav["nb_sample/nb_sample"].value) / format["sample_per_sec"].value) | |
64 | and 0 < format["sample_per_sec"].value): | |
65 | self.duration = timedelta(seconds=float( | |
66 | wav["nb_sample/nb_sample"].value) / format["sample_per_sec"].value) | |
66 | 67 | if format["codec"].value in UNCOMPRESSED_AUDIO: |
67 | 68 | # Codec with fixed bit rate |
68 | self.bit_rate = format["nb_channel"].value * format["bit_per_sample"].value * format["sample_per_sec"].value | |
69 | self.bit_rate = format[ | |
70 | "nb_channel"].value * format["bit_per_sample"].value * format["sample_per_sec"].value | |
69 | 71 | if (not self.has("duration") |
70 | and "audio_data/size" in wav | |
71 | and self.has("bit_rate")): | |
72 | duration = float(wav["audio_data/size"].value) * 8 / self.get('bit_rate') | |
72 | and "audio_data/size" in wav | |
73 | and self.has("bit_rate")): | |
74 | duration = float(wav["audio_data/size"].value) * \ | |
75 | 8 / self.get('bit_rate') | |
73 | 76 | self.duration = timedelta(seconds=duration) |
74 | 77 | |
75 | 78 | def extractInfo(self, fieldset): |
90 | 93 | fps = float(header["rate"].value) / header["scale"].value |
91 | 94 | meta.frame_rate = fps |
92 | 95 | if 0 < fps: |
93 | self.duration = meta.duration = timedelta(seconds=float(header["length"].value) / fps) | |
96 | self.duration = meta.duration = timedelta( | |
97 | seconds=float(header["length"].value) / fps) | |
94 | 98 | |
95 | 99 | if "../stream_fmt/width" in header: |
96 | 100 | format = header["../stream_fmt"] |
111 | 115 | if "../stream_hdr" in format: |
112 | 116 | header = format["../stream_hdr"] |
113 | 117 | if header["rate"].value and header["scale"].value: |
114 | frame_rate = float(header["rate"].value) / header["scale"].value | |
115 | meta.duration = timedelta(seconds=float(header["length"].value) / frame_rate) | |
118 | frame_rate = float( | |
119 | header["rate"].value) / header["scale"].value | |
120 | meta.duration = timedelta(seconds=float( | |
121 | header["length"].value) / frame_rate) | |
116 | 122 | if header["fourcc"].value != "": |
117 | 123 | meta.compression = "%s (fourcc:\"%s\")" \ |
118 | 124 | % (format["codec"].display, header["fourcc"].value) |
126 | 132 | uncompr = meta.get('bit_rate', 0) |
127 | 133 | if not uncompr: |
128 | 134 | return |
129 | compr = meta.get('nb_channel') * meta.get('sample_rate') * meta.get('bits_per_sample', default=16) | |
135 | compr = meta.get('nb_channel') * meta.get('sample_rate') * \ | |
136 | meta.get('bits_per_sample', default=16) | |
130 | 137 | if not compr: |
131 | 138 | return |
132 | 139 | meta.compr_rate = float(compr) / uncompr |
165 | 172 | |
166 | 173 | # Compute global bit rate |
167 | 174 | if self.has("duration") and "/movie/size" in headers: |
168 | self.bit_rate = float(headers["/movie/size"].value) * 8 / timedelta2seconds(self.get('duration')) | |
175 | self.bit_rate = float( | |
176 | headers["/movie/size"].value) * 8 / timedelta2seconds(self.get('duration')) | |
169 | 177 | |
170 | 178 | # Video has index? |
171 | 179 | if "/index" in headers: |
4 | 4 | http://standards.ieee.org/regauth/oui/oui.txt |
5 | 5 | """ |
6 | 6 | |
7 | REGISTERED_OUID = { # noqa | |
7 | REGISTERED_OUID = { # noqa | |
8 | 8 | 0x000000: u'XEROX CORPORATION', |
9 | 9 | 0x000001: u'XEROX CORPORATION', |
10 | 10 | 0x000002: u'XEROX CORPORATION', |
8 | 8 | Store self.size data rates to compute good average speed. |
9 | 9 | Don't compute average before self.min_size values are computed. |
10 | 10 | """ |
11 | ||
11 | 12 | def __init__(self, offset, size=20, min_size=3): |
12 | 13 | self.last_offset = offset |
13 | 14 | self.last_time = time() |
0 | 0 | #!/usr/bin/env python3 |
1 | import sys, os | |
1 | import sys | |
2 | import os | |
2 | 3 | |
3 | 4 | from gi.repository import Gtk |
4 | 5 | |
6 | 7 | from hachoir.metadata import extractMetadata |
7 | 8 | from hachoir.metadata.metadata import MultipleMetadata |
8 | 9 | |
10 | ||
9 | 11 | class Gui: |
12 | ||
10 | 13 | def __init__(self): |
11 | 14 | self.main_window = Gtk.Window() |
12 | 15 | self.main_window.set_border_width(5) |
24 | 27 | self.main_vbox.pack_start(self.select_hbox, False, True, 0) |
25 | 28 | |
26 | 29 | self.metadata_table = Gtk.Table(1, 1) |
27 | self.metadata_table.attach(Gtk.Label("Select a file to view metadata information..."), 0, 1, 0, 1) | |
30 | self.metadata_table.attach( | |
31 | Gtk.Label("Select a file to view metadata information..."), 0, 1, 0, 1) | |
28 | 32 | self.main_vbox.pack_start(self.metadata_table, True, True, 0) |
29 | 33 | |
30 | 34 | self.main_window.add(self.main_vbox) |
35 | 39 | |
36 | 40 | def _select_clicked(self, widget): |
37 | 41 | file_chooser = Gtk.FileChooserDialog("Ouvrir..", None, |
38 | Gtk.FILE_CHOOSER_ACTION_OPEN, | |
39 | (Gtk.STOCK_CANCEL, Gtk.RESPONSE_CANCEL, | |
40 | Gtk.STOCK_OPEN, Gtk.RESPONSE_OK)) | |
42 | Gtk.FILE_CHOOSER_ACTION_OPEN, | |
43 | (Gtk.STOCK_CANCEL, Gtk.RESPONSE_CANCEL, | |
44 | Gtk.STOCK_OPEN, Gtk.RESPONSE_OK)) | |
41 | 45 | file_chooser.set_default_response(Gtk.RESPONSE_OK) |
42 | 46 | file_chooser.show() |
43 | 47 | |
58 | 62 | self.main_vbox.pack_start(self.metadata_table, True, True, 0) |
59 | 63 | |
60 | 64 | if metadata is None: |
61 | self.metadata_table.attach(Gtk.Label("Unknown file format"), 0, 1, 0, 1) | |
65 | self.metadata_table.attach( | |
66 | Gtk.Label("Unknown file format"), 0, 1, 0, 1) | |
62 | 67 | else: |
63 | 68 | total = 1 |
64 | 69 | for data in sorted(metadata): |
68 | 73 | for item in data.values: |
69 | 74 | self.metadata_table.resize(total, 2) |
70 | 75 | value = item.text |
71 | self.metadata_table.attach(Gtk.Label(title + ":"), 0, 1, total-1, total) | |
72 | self.metadata_table.attach(Gtk.Label(value), 1, 2, total-1, total) | |
76 | self.metadata_table.attach( | |
77 | Gtk.Label(title + ":"), 0, 1, total - 1, total) | |
78 | self.metadata_table.attach( | |
79 | Gtk.Label(value), 1, 2, total - 1, total) | |
73 | 80 | total += 1 |
74 | 81 | self.metadata_table.show_all() |
75 | 82 | |
94 | 101 | |
95 | 102 | if __name__ == "__main__": |
96 | 103 | Gui().main() |
97 |
0 | import wx, os | |
0 | import wx | |
1 | import os | |
1 | 2 | from hachoir.core.i18n import _ |
3 | ||
2 | 4 | |
3 | 5 | def file_open_dialog(): |
4 | 6 | dialog_style = wx.OPEN | wx.FILE_MUST_EXIST |
5 | 7 | |
6 | 8 | dialog = wx.FileDialog( |
7 | None, message = _('Open'), | |
8 | defaultDir = os.getcwd(), | |
9 | defaultFile = '', style = dialog_style) | |
9 | None, message=_('Open'), | |
10 | defaultDir=os.getcwd(), | |
11 | defaultFile='', style=dialog_style) | |
10 | 12 | |
11 | 13 | return dialog |
14 | ||
12 | 15 | |
13 | 16 | def file_save_dialog(title): |
14 | 17 | dialog_style = wx.SAVE |
15 | 18 | |
16 | 19 | dialog = wx.FileDialog( |
17 | None, message = title, | |
18 | defaultDir = os.getcwd(), | |
19 | defaultFile = '', style = dialog_style) | |
20 | None, message=title, | |
21 | defaultDir=os.getcwd(), | |
22 | defaultFile='', style=dialog_style) | |
20 | 23 | |
21 | 24 | return dialog |
1 | 1 | from hachoir_wx.field_view.mutator import convert_field |
2 | 2 | from hachoir_wx.field_view.stubs import can_convert |
3 | 3 | |
4 | ||
4 | 5 | class core_type_menu_imp_t: |
6 | ||
5 | 7 | def __init__(self): |
6 | 8 | self.cur_field = None |
7 | 9 |
0 | 0 | from hachoir_wx.field_view.stubs import save_substream_to_disk |
1 | 1 | from hachoir.core.i18n import _ |
2 | 2 | |
3 | ||
3 | 4 | class field_menu_imp_t: |
5 | ||
4 | 6 | def on_field_set_ready(self, dispatcher, fields): |
5 | 7 | assert fields is not None |
6 | 8 | self.fields = fields |
44 | 46 | self.dispatcher.trigger('field_open_window_here', self.selected) |
45 | 47 | |
46 | 48 | def on_dump_to_disk(self, event): |
47 | dump_path = self.view.ask_for_dump_file(_('Dump "' + self.selected._getPath() + '" To Disk...')) | |
49 | dump_path = self.view.ask_for_dump_file( | |
50 | _('Dump "' + self.selected._getPath() + '" To Disk...')) | |
48 | 51 | if dump_path is not None: |
49 | 52 | save_substream_to_disk(self.selected, dump_path) |
50 |
0 | 0 | from wx import GetNumberFromUser |
1 | 1 | from hachoir.core.i18n import _ |
2 | 2 | |
3 | ||
3 | 4 | class field_split_menu_t: |
5 | ||
4 | 6 | def __init__(self, parent, menu): |
5 | 7 | self.parent = parent |
6 | 8 | self.menu = menu |
7 | self.Bind = self.menu.Bind # see note in field_menu.py | |
9 | self.Bind = self.menu.Bind # see note in field_menu.py | |
8 | 10 | |
9 | 11 | def ask_split(self, caption, min, max): |
10 | 12 | num = GetNumberFromUser(_('Enter split offset:'), '', |
1 | 1 | from hachoir.field import RawBytes, RawBits |
2 | 2 | from hachoir.core.i18n import _ |
3 | 3 | |
4 | ||
4 | 5 | class field_split_menu_imp_t: |
6 | ||
5 | 7 | def on_field_split_menu_ready(self, dispatcher, view): |
6 | 8 | assert view is not None |
7 | 9 | self.view = view |
20 | 22 | def split_field(self, caption, field, split_type, size_func): |
21 | 23 | offset = self.view.ask_split(caption, 1, size_func(field) - 1) |
22 | 24 | if offset is not None: |
23 | new_fields = split_field(field, offset, field._getName(), split_type, size_func) | |
25 | new_fields = split_field( | |
26 | field, offset, field._getName(), split_type, size_func) | |
24 | 27 | |
25 | 28 | return offset |
2 | 2 | from sys import maxsize |
3 | 3 | from hachoir.core.i18n import _ |
4 | 4 | |
5 | ||
5 | 6 | class field_view_t(ListCtrl, ListCtrlAutoWidthMixin): |
7 | ||
6 | 8 | def __init__(self): |
7 | 9 | self.cols = {} |
8 | 10 | |
13 | 15 | def post_init(self): |
14 | 16 | ListCtrlAutoWidthMixin.__init__(self) |
15 | 17 | |
16 | columns = [_('address'), _('name'), _('type'), _('size'), _('data'), _('description')] | |
18 | columns = [_('address'), _('name'), _('type'), | |
19 | _('size'), _('data'), _('description')] | |
17 | 20 | for name in columns: |
18 | 21 | self.append_column(name) |
19 | 22 | self.col_min_width = [len(s) for s in columns] |
29 | 32 | def append_column(self, name): |
30 | 33 | index = self.GetColumnCount() |
31 | 34 | self.cols[name] = index |
32 | self.InsertColumn(col = index, heading = name) | |
35 | self.InsertColumn(col=index, heading=name) | |
33 | 36 | |
34 | 37 | def get_selected(self, name): |
35 | 38 | return self.GetItem(self.GetFocusedItem(), self.cols[_('name')]).GetText() |
44 | 47 | return self.OnGetItemText_imp(item, col) |
45 | 48 | |
46 | 49 | def get_col_index(self, name): |
47 | return self.cols[name] | |
50 | return self.cols[name] | |
48 | 51 | |
49 | 52 | def get_col_count(self): |
50 | return len(self.cols) | |
53 | return len(self.cols) | |
51 | 54 | |
52 | 55 | def resize_column(self, col_index, width): |
53 | 56 | width = max(self.col_min_width[col_index], width) + 1 |
2 | 2 | |
3 | 3 | MAXITEMS = 1000 |
4 | 4 | |
5 | ||
5 | 6 | class field_view_imp_t: |
7 | ||
6 | 8 | def __init__(self): |
7 | 9 | self.addr_func = lambda field: field._getAbsoluteAddress() |
8 | 10 | self.format_addr = lambda field: format_addr_hex(self.addr_func(field)) |
24 | 26 | assert view is not None |
25 | 27 | |
26 | 28 | # register callbacks before activating the field view |
27 | view.register_callback(cbGetItemText = self.OnGetItemTextImp) | |
29 | view.register_callback(cbGetItemText=self.OnGetItemTextImp) | |
28 | 30 | |
29 | 31 | self.view = view |
30 | 32 | self.fill_view() |
91 | 93 | width = 0 |
92 | 94 | func = self.col_str_table[col] |
93 | 95 | # when fields has more than 20 rows, they are probably similar. |
94 | # Therefore this routine only checks the first 10 rows and last 10 rows. | |
96 | # Therefore this routine only checks the first 10 rows and last 10 | |
97 | # rows. | |
95 | 98 | |
96 | 99 | if field_count <= 20: |
97 | 100 | field_range = [(0, field_count)] |
117 | 120 | else: |
118 | 121 | parent_count = 0 |
119 | 122 | try: |
120 | self.fields[item+MAXITEMS] | |
121 | if item+MAXITEMS+parent_count > self.view.GetItemCount(): | |
122 | self.view.SetItemCount(item+MAXITEMS+parent_count) | |
123 | self.fields[item + MAXITEMS] | |
124 | if item + MAXITEMS + parent_count > self.view.GetItemCount(): | |
125 | self.view.SetItemCount(item + MAXITEMS + parent_count) | |
123 | 126 | except: |
124 | 127 | if len(self.fields) + parent_count != self.view.GetItemCount(): |
125 | self.view.SetItemCount(len(self.fields)+parent_count) | |
128 | self.view.SetItemCount(len(self.fields) + parent_count) | |
126 | 129 | field = self.fields[item] |
127 | 130 | return self.col_str_table[col](field) |
128 | 131 |
0 | 0 | def format_addr_dec(addr): |
1 | 1 | return "%08d.%01d" % divmod(addr, 8) |
2 | ||
2 | 3 | |
3 | 4 | def format_addr_hex(addr): |
4 | 5 | return "%08x.%01d" % divmod(addr, 8) |
5 | 6 | |
7 | ||
6 | 8 | def format_size(size): |
7 | 9 | return "%08u.%01d" % divmod(size, 8) |
10 | ||
8 | 11 | |
9 | 12 | def format_data(field): |
10 | 13 | data = '' |
14 | 17 | |
15 | 18 | return data |
16 | 19 | |
20 | ||
17 | 21 | def format_name(field): |
18 | 22 | name = field._getName() |
19 | 23 | if field.is_field_set: |
21 | 25 | |
22 | 26 | return name |
23 | 27 | |
28 | ||
24 | 29 | def format_desc(field): |
25 | 30 | if field.description: |
26 | 31 | return str(field.description) |
27 | 32 | return '' |
28 |
4 | 4 | from hachoir.core.tools import alignValue |
5 | 5 | from hachoir.stream.input import FileFromInputStream |
6 | 6 | |
7 | ||
7 | 8 | def field_index(field_set, field): |
8 | 9 | return field_set._fields.index(field._getName()) |
10 | ||
9 | 11 | |
10 | 12 | def field_from_index(field_set, index): |
11 | 13 | return field_set._fields.values[index] |
12 | 14 | |
15 | ||
13 | 16 | def has_static_size(type): |
14 | 17 | return isinstance(type.static_size, int) |
18 | ||
15 | 19 | |
16 | 20 | def can_convert(from_field, to_type): |
17 | 21 | if has_static_size(from_field) and has_static_size(to_type): |
21 | 25 | else: |
22 | 26 | return False |
23 | 27 | |
28 | ||
24 | 29 | def field_type_name(field): |
25 | 30 | return field.__class__.__name__ |
31 | ||
26 | 32 | |
27 | 33 | def convert_size(from_field, to_type): |
28 | 34 | if not(('Byte' in field_type_name(from_field)) ^ ('Byte' in to_type.__name__)): |
32 | 38 | else: |
33 | 39 | return from_field._getSize() // 8 |
34 | 40 | |
41 | ||
35 | 42 | def save_substream_to_disk(field, dest_path): |
36 | 43 | dest_stream = open(dest_path, 'wb') |
37 | 44 | f = FileFromInputStream(field.getSubIStream()) |
38 | 45 | dest_stream.write(f.read()) |
39 | 46 | dest_stream.close() |
40 |
0 | 0 | from wx import Frame, PreFrame |
1 | 1 | |
2 | ||
2 | 3 | class frame_view_t(Frame): |
4 | ||
3 | 5 | def __init__(self): |
4 | 6 | pre = PreFrame() |
5 | 7 | self.PostCreate(pre) |
6 | 8 | |
7 | 9 | def ready(self): |
8 | 10 | self.dispatcher.trigger('frame_view_ready', self) |
9 |
0 | 0 | class frame_view_imp_t: |
1 | ||
1 | 2 | def on_frame_view_ready(self, dispatcher, frame_view): |
2 | 3 | assert frame_view is not None |
3 | 4 | self.view = frame_view |
11 | 12 | |
12 | 13 | def format_title(self, field): |
13 | 14 | field_path = field._getPath() |
14 | return self.filename+'/'+field_path[1:] | |
15 | return self.filename + '/' + field_path[1:] | |
15 | 16 | |
16 | 17 | def on_field_activated(self, dispatcher, field): |
17 | 18 | self.view.SetTitle(self.format_title(field)) |
1 | 1 | from .frame_view_fwd import frame_view_fwd_t |
2 | 2 | |
3 | 3 | from hachoir_wx.resource import get_frame |
4 | ||
4 | 5 | |
5 | 6 | def setup_frame_view(dispatcher): |
6 | 7 | print('[+] Setup frame view') |
0 | 0 | # Windows wx compatibility |
1 | 1 | |
2 | ||
2 | 3 | def get_width_chars(view): |
3 | return ((view.GetClientSize()[0]-3) // (view.GetCharWidth()-1) - 1) // 3 | |
4 | return ((view.GetClientSize()[0] - 3) // (view.GetCharWidth() - 1) - 1) // 3 | |
5 | ||
4 | 6 | |
5 | 7 | def get_height_chars(view): |
6 | 8 | return view.GetClientSize()[1] // view.GetCharHeight() |
0 | 0 | from wx import TextCtrl, TextAttr, PreTextCtrl |
1 | 1 | from .stubs import to_ascii, to_hex, calc_char_range, calc_ascii_range, clamp_range |
2 | 2 | from hachoir_wx.hex_view import get_width_chars, get_height_chars |
3 | ||
3 | 4 | |
4 | 5 | class hex_view_t(TextCtrl): |
5 | 6 | default_style = TextAttr() |
26 | 27 | self.Refresh() |
27 | 28 | |
28 | 29 | def mark_range(self, start, size): |
29 | mark_start, mark_end = calc_char_range(start, start + size, self.get_width_chars()) | |
30 | mark_start, mark_end = calc_char_range( | |
31 | start, start + size, self.get_width_chars()) | |
30 | 32 | |
31 | 33 | mark_start = clamp_range(mark_start, 0, self.get_size()) |
32 | 34 | mark_end = clamp_range(mark_end, 0, self.get_size()) |
34 | 36 | self.SetStyle(mark_start, mark_end, self.highlight_style) |
35 | 37 | self.Refresh() |
36 | 38 | |
37 | mark_start, mark_end = calc_ascii_range(start, start + size, self.get_width_chars()) | |
39 | mark_start, mark_end = calc_ascii_range( | |
40 | start, start + size, self.get_width_chars()) | |
38 | 41 | |
39 | 42 | mark_start = clamp_range(mark_start, 0, self.get_ascii_size()) |
40 | 43 | mark_end = clamp_range(mark_end, 0, self.get_ascii_size()) |
52 | 55 | def get_size(self): |
53 | 56 | return len(self.GetValue()) |
54 | 57 | |
58 | ||
55 | 59 | def get_page_size(view): |
56 | 60 | return view.get_width_chars() * view.get_height_chars() |
0 | 0 | from wx import ScrollBar, PreScrollBar |
1 | 1 | |
2 | ||
2 | 3 | class hex_view_scroll_t(ScrollBar): |
4 | ||
3 | 5 | def __init__(self): |
4 | 6 | pre = PreScrollBar() |
5 | 7 | self.PostCreate(pre) |
6 | 8 | |
7 | 9 | def ready(self): |
8 | 10 | self.dispatcher.trigger('hex_view_scroll_ready', self) |
9 |
0 | 0 | from math import ceil |
1 | 1 | from .stubs import byte_addr, get_file_size, get_page_num |
2 | 2 | |
3 | ||
3 | 4 | class hex_view_scroll_imp_t: |
5 | ||
4 | 6 | def on_file_ready(self, dispatcher, file): |
5 | 7 | assert file is not None |
6 | 8 | self.file = file |
21 | 23 | cur_height = self.offset_to_thumb(pos) |
22 | 24 | total_height = int(ceil(get_file_size(self.file) / float(page_width))) |
23 | 25 | |
24 | self.view.SetScrollbar(cur_height, page_height, total_height, page_height) | |
26 | self.view.SetScrollbar(cur_height, page_height, | |
27 | total_height, page_height) | |
25 | 28 | |
26 | 29 | def on_field_selected(self, dispatcher, field): |
27 | 30 | offset = byte_addr(field._getAbsoluteAddress()) |
34 | 37 | |
35 | 38 | def set_mappers(self, page_width): |
36 | 39 | self.thumb_to_offset = lambda thumb_pos: thumb_pos * page_width |
37 | self.offset_to_thumb = lambda offset: get_page_num(offset = offset, | |
38 | page_width = page_width) | |
40 | self.offset_to_thumb = lambda offset: get_page_num(offset=offset, | |
41 | page_width=page_width) | |
39 | 42 | |
40 | 43 | def on_scrolled(self): |
41 | 44 | offset = self.thumb_to_offset(self.view.GetThumbPosition()) |
0 | 0 | from hachoir.core.tools import alignValue |
1 | 1 | from hachoir.core.error import warning |
2 | ||
2 | 3 | |
3 | 4 | def byte_addr(bit): |
4 | 5 | return bit // 8 |
5 | 6 | |
7 | ||
6 | 8 | def bit_addr(byte): |
7 | 9 | return byte * 8 |
10 | ||
8 | 11 | |
9 | 12 | def get_file_size(file): |
10 | 13 | pos = file.tell() |
14 | 17 | |
15 | 18 | return size |
16 | 19 | |
20 | ||
17 | 21 | def to_hex(data, width=None): |
18 | 22 | hex_data = '' |
19 | 23 | for i in range(len(data)): |
20 | 24 | hex_data += "%02x" % ord(data[i]) |
21 | if width and (i+1)%width==0: | |
25 | if width and (i + 1) % width == 0: | |
22 | 26 | hex_data += '\n' |
23 | 27 | else: |
24 | 28 | hex_data += ' ' |
25 | 29 | |
26 | 30 | return hex_data.rstrip(' ') |
31 | ||
27 | 32 | |
28 | 33 | def to_ascii(data, width=None): |
29 | 34 | ascii_data = '' |
32 | 37 | ascii_data += data[i] |
33 | 38 | else: |
34 | 39 | ascii_data += '.' |
35 | if width and (i+1)%width==0: | |
40 | if width and (i + 1) % width == 0: | |
36 | 41 | ascii_data += '\n' |
37 | 42 | |
38 | 43 | return ascii_data |
39 | 44 | |
45 | ||
40 | 46 | def calc_byte_range(start, end): |
41 | 47 | return byte_addr(start), byte_addr(alignValue(end, 8)) |
48 | ||
42 | 49 | |
43 | 50 | def calc_ascii_range(start, end, width=None): |
44 | 51 | aligned_start, aligned_end = calc_byte_range(start, end) |
48 | 55 | |
49 | 56 | return char_start, char_end |
50 | 57 | |
58 | ||
51 | 59 | def calc_ascii_pos(byte_pos, width=None): |
52 | 60 | if width: |
53 | line_offset = (byte_pos // width) * (width+1) | |
61 | line_offset = (byte_pos // width) * (width + 1) | |
54 | 62 | return line_offset + (byte_pos % width) |
55 | 63 | return byte_pos |
64 | ||
56 | 65 | |
57 | 66 | def calc_char_range(start, end, width=None): |
58 | 67 | aligned_start, aligned_end = calc_byte_range(start, end) |
59 | 68 | |
60 | 69 | char_start = calc_char_pos(aligned_start) |
61 | char_end = calc_char_pos(aligned_end)-1 | |
70 | char_end = calc_char_pos(aligned_end) - 1 | |
62 | 71 | |
63 | 72 | return char_start, char_end |
64 | 73 | |
74 | ||
65 | 75 | def calc_char_pos(byte_pos): |
66 | 76 | return byte_pos * 3 |
77 | ||
67 | 78 | |
68 | 79 | def clamp_range(what, begin, end): |
69 | 80 | what = max(what, begin) |
70 | 81 | what = min(what, end) |
71 | 82 | return what |
83 | ||
72 | 84 | |
73 | 85 | def safe_seek(file, where): |
74 | 86 | try: |
80 | 92 | |
81 | 93 | return True |
82 | 94 | |
95 | ||
83 | 96 | def get_page_num(offset, page_width): |
84 | 97 | return offset // page_width |
85 | 98 | |
99 | ||
86 | 100 | def get_page_offset(offset, page_width): |
87 | 101 | return get_page_num(offset, page_width) * page_width |
102 | ||
88 | 103 | |
89 | 104 | def calc_field_mark(offset, field): |
90 | 105 | start = field._getAbsoluteAddress() - bit_addr(offset) |
0 | 0 | import os |
1 | 1 | from wx.xrc import XmlResource, XRCCTRL |
2 | 2 | |
3 | ||
3 | 4 | def get_resource(): |
4 | filename = os.path.join(os.getcwd(), os.path.dirname(__file__), 'hachoir_wx.xrc') | |
5 | filename = os.path.join( | |
6 | os.getcwd(), os.path.dirname(__file__), 'hachoir_wx.xrc') | |
5 | 7 | return XmlResource(filename) |
8 | ||
6 | 9 | |
7 | 10 | def get_frame(name): |
8 | 11 | return get_resource().LoadFrame(None, name) |
9 | 12 | |
13 | ||
10 | 14 | def get_child_control(parent, child): |
11 | 15 | return XRCCTRL(parent, child) |
16 | ||
12 | 17 | |
13 | 18 | def get_menu_bar(name): |
14 | 19 | return get_resource().LoadMenuBar(name) |
15 | 20 | |
21 | ||
16 | 22 | def get_menu_from_bar(menu_bar, menu_name): |
17 | 23 | menu_index = menu_bar.FindMenu(menu_name) |
18 | assert -1 != menu_index, 'cannot find menu ' + menu_name + ' in menu bar ' + menu_bar.GetTitle() | |
24 | assert -1 != menu_index, 'cannot find menu ' + \ | |
25 | menu_name + ' in menu bar ' + menu_bar.GetTitle() | |
19 | 26 | return menu_bar.GetMenu(menu_index) |
20 |
1 | 1 | VERSION = "0.3.1" |
2 | 2 | WEBSITE = 'http://bitbucket.org/haypo/hachoir/wiki/hachoir-wx' |
3 | 3 | LICENSE = 'GNU GPL v2' |
4 |
11 | 11 | 'Operating System :: OS Independent', |
12 | 12 | 'Natural Language :: English', |
13 | 13 | 'Programming Language :: Python'] |
14 | ||
14 | 15 | |
15 | 16 | def main(): |
16 | 17 | if "--setuptools" in sys.argv: |
35 | 36 | exitcode = 1 |
36 | 37 | if exitcode: |
37 | 38 | if path.exists(dialog_python): |
38 | print("Warning: unable to recompile dialog.ui to dialog_ui.py using pyuic4", file=sys.stderr) | |
39 | print('(use command "%s --disable-qt" to disable this warning)' % ' '.join(sys.argv), file=sys.stderr) | |
39 | print( | |
40 | "Warning: unable to recompile dialog.ui to dialog_ui.py using pyuic4", file=sys.stderr) | |
41 | print('(use command "%s --disable-qt" to disable this warning)' % | |
42 | ' '.join(sys.argv), file=sys.stderr) | |
40 | 43 | print(file=sys.stderr) |
41 | 44 | else: |
42 | print("ERROR: Unable to compile dialog.ui to dialog_ui.py using pyuic4", file=sys.stderr) | |
43 | print('Use command "%s --disable-qt" to skip hachoir-metadata-qt' % ' '.join(sys.argv), file=sys.stderr) | |
44 | print('pyuic4 is included in the PyQt4 development package', file=sys.stderr) | |
45 | print( | |
46 | "ERROR: Unable to compile dialog.ui to dialog_ui.py using pyuic4", file=sys.stderr) | |
47 | print('Use command "%s --disable-qt" to skip hachoir-metadata-qt' % | |
48 | ' '.join(sys.argv), file=sys.stderr) | |
49 | print('pyuic4 is included in the PyQt4 development package', | |
50 | file=sys.stderr) | |
45 | 51 | sys.exit(1) |
46 | 52 | PACKAGES.append("hachoir.metadata.qt") |
47 | 53 | |
48 | hachoir.metadata = load_source("version", path.join("hachoir.metadata", "version.py")) | |
54 | hachoir.metadata = load_source( | |
55 | "version", path.join("hachoir.metadata", "version.py")) | |
49 | 56 | long_description = open('README').read() + open('ChangeLog').read() |
50 | 57 | install_options = { |
51 | 58 | "name": hachoir.metadata.PACKAGE, |
61 | 68 | "packages": PACKAGES, |
62 | 69 | } |
63 | 70 | if use_setuptools: |
64 | install_options["install_requires"] = ["hachoir-core>=1.3", "hachoir-parser>=1.3"] | |
71 | install_options["install_requires"] = [ | |
72 | "hachoir-core>=1.3", "hachoir-parser>=1.3"] | |
65 | 73 | install_options["zip_safe"] = True |
66 | 74 | setup(**install_options) |
67 | 75 | |
68 | 76 | if __name__ == "__main__": |
69 | 77 | main() |
70 |
28 | 28 | # 1 times on 20 tries |
29 | 29 | TRUNCATE_RATE = 20 |
30 | 30 | |
31 | ||
31 | 32 | class UndoMangle: |
33 | ||
32 | 34 | def __init__(self, fuzz): |
33 | 35 | self.data = fuzz.data.tostring() |
34 | 36 | self.orig = fuzz.is_original |
37 | 39 | fuzz.data = array('B', self.data) |
38 | 40 | fuzz.is_original = self.orig |
39 | 41 | |
42 | ||
40 | 43 | class UndoTruncate: |
44 | ||
41 | 45 | def __init__(self, fuzz): |
42 | 46 | self.data = fuzz.data |
43 | 47 | self.orig = fuzz.is_original |
46 | 50 | fuzz.data = self.data |
47 | 51 | fuzz.is_original = self.orig |
48 | 52 | |
53 | ||
49 | 54 | class FileFuzzer: |
55 | ||
50 | 56 | def __init__(self, fuzzer, filename): |
51 | 57 | self.fuzzer = fuzzer |
52 | 58 | self.verbose = fuzzer.verbose |
85 | 91 | self.nb_truncate, percent, self.size)) |
86 | 92 | |
87 | 93 | def warning(self, message): |
88 | print(" %s (%s): %s" % (basename(self.filename), self.nb_extract, message)) | |
94 | print(" %s (%s): %s" % | |
95 | (basename(self.filename), self.nb_extract, message)) | |
89 | 96 | |
90 | 97 | def info(self, message): |
91 | 98 | if self.verbose: |
111 | 118 | |
112 | 119 | # Truncate |
113 | 120 | self.nb_truncate += 1 |
114 | new_size = randint(MIN_SIZE, len(self.data)-1) | |
121 | new_size = randint(MIN_SIZE, len(self.data) - 1) | |
115 | 122 | self.warning("Truncate #%s (%s bytes)" % (self.nb_truncate, new_size)) |
116 | 123 | self.data = self.data[:new_size] |
117 | 124 | self.is_original = False |
129 | 136 | self.undo = None |
130 | 137 | |
131 | 138 | # Update mangle percent |
132 | percent = max(self.mangle_percent - MANGLE_PERCENT_INCR, MIN_MANGLE_PERCENT) | |
139 | percent = max(self.mangle_percent - | |
140 | MANGLE_PERCENT_INCR, MIN_MANGLE_PERCENT) | |
133 | 141 | if self.mangle_percent != percent: |
134 | 142 | self.mangle_percent = percent |
135 | self.info("Set mangle percent to: %u%%" % int(self.mangle_percent*100)) | |
143 | self.info("Set mangle percent to: %u%%" % | |
144 | int(self.mangle_percent * 100)) | |
136 | 145 | return True |
137 | 146 | |
138 | 147 | def extract(self): |
177 | 186 | def keepFile(self, prefix): |
178 | 187 | data = self.data.tostring() |
179 | 188 | uniq_id = generateUniqueID(data) |
180 | filename="%s-%s" % (uniq_id, basename(self.filename)) | |
189 | filename = "%s-%s" % (uniq_id, basename(self.filename)) | |
181 | 190 | if prefix: |
182 | 191 | filename = "%s-%s" % (prefix, filename) |
183 | 192 | filename = path.join(self.fuzzer.error_dir, filename) |
184 | 193 | open(filename, "wb").write(data) |
185 | 194 | print("=> Store file %s" % filename) |
186 |
1 | 1 | |
2 | 2 | if platform == 'win32': |
3 | 3 | from win32process import (GetCurrentProcess, SetPriorityClass, |
4 | BELOW_NORMAL_PRIORITY_CLASS) | |
4 | BELOW_NORMAL_PRIORITY_CLASS) | |
5 | 5 | |
6 | 6 | def beNice(): |
7 | 7 | process = GetCurrentProcess() |
20 | 20 | |
21 | 21 | try: |
22 | 22 | import sha |
23 | ||
23 | 24 | def generateUniqueID(data): |
24 | 25 | return sha.new(data).hexdigest() |
25 | 26 | except ImportError: |
28 | 29 | return generateUniqueID.sequence |
29 | 30 | generateUniqueID.sequence = 0 |
30 | 31 | |
32 | ||
31 | 33 | def getFilesize(file): |
32 | 34 | file.seek(0, 2) |
33 | 35 | size = file.tell() |
34 | 36 | file.seek(0, 0) |
35 | 37 | return size |
36 |
27 | 27 | raise |
28 | 28 | |
29 | 29 | if not hasattr(fuse, '__version__'): |
30 | raise RuntimeError("your fuse-py doesn't know of fuse.__version__, probably it's too old.") | |
30 | raise RuntimeError( | |
31 | "your fuse-py doesn't know of fuse.__version__, probably it's too old.") | |
31 | 32 | |
32 | 33 | # This setting is optional, but it ensures that this class will keep |
33 | 34 | # working after a future API revision |
34 | 35 | fuse.fuse_python_api = (0, 2) |
35 | 36 | |
37 | ||
36 | 38 | class MyStat(fuse.Stat): |
39 | ||
37 | 40 | def __init__(self): |
38 | 41 | self.st_mode = 0 |
39 | 42 | self.st_ino = 0 |
46 | 49 | self.st_mtime = 0 |
47 | 50 | self.st_ctime = 0 |
48 | 51 | |
52 | ||
49 | 53 | class HelloFS(Fuse): |
54 | ||
50 | 55 | def __init__(self, input_filename, **kw): |
51 | 56 | Fuse.__init__(self, **kw) |
52 | 57 | log.setFilename("/home/haypo/fuse_log") |
77 | 82 | raise |
78 | 83 | |
79 | 84 | def fieldValue(self, field): |
80 | return makePrintable(field.display, "ISO-8859-1")+"\n" | |
85 | return makePrintable(field.display, "ISO-8859-1") + "\n" | |
81 | 86 | |
82 | 87 | def getattr(self, path): |
83 | 88 | st = MyStat() |
153 | 158 | count = len(fieldset) |
154 | 159 | if count % 10: |
155 | 160 | count += 10 - (count % 10) |
156 | format = "%%0%ud-%%s" % (count//10) | |
161 | format = "%%0%ud-%%s" % (count // 10) | |
157 | 162 | |
158 | 163 | # Create entries |
159 | 164 | for index, field in enumerate(fieldset): |
160 | name = format % (1+index, field.name) | |
165 | name = format % (1 + index, field.name) | |
161 | 166 | entry = fuse.Direntry(name) |
162 | 167 | if field.is_field_set: |
163 | 168 | entry.type = stat.S_IFDIR |
207 | 212 | return '' |
208 | 213 | if offset + size > slen: |
209 | 214 | size = slen - offset |
210 | data = data[offset:offset+size] | |
215 | data = data[offset:offset + size] | |
211 | 216 | log.info("=> %s" % repr(data)) |
212 | 217 | return data |
213 | 218 | |
217 | 222 | def truncate(self, *args): |
218 | 223 | log.info("truncate(): TODO!") |
219 | 224 | |
225 | ||
220 | 226 | def main(): |
221 | usage=""" | |
227 | usage = """ | |
222 | 228 | Userspace hello example |
223 | 229 | |
224 | 230 | """ + Fuse.fusage |
0 | 0 | #!/usr/bin/env python3 |
1 | 1 | |
2 | 2 | from hachoir.editor import (createEditor as hachoirCreateEditor, |
3 | NewFieldSet, EditableInteger, EditableString, EditableBytes) | |
3 | NewFieldSet, EditableInteger, EditableString, EditableBytes) | |
4 | 4 | from hachoir.stream import FileOutputStream |
5 | 5 | from hachoir.parser import createParser |
6 | 6 | from hachoir.parser.image import PngFile |
8 | 8 | from sys import argv, stdin, stdout, stderr, exit |
9 | 9 | import zlib |
10 | 10 | |
11 | ||
11 | 12 | class InjecterError(Exception): |
12 | 13 | pass |
13 | 14 | |
15 | ||
14 | 16 | class Injecter: |
17 | ||
15 | 18 | def __init__(self, editor): |
16 | 19 | self.editor = editor |
17 | 20 | |
18 | 21 | def getMaxSize(self): |
19 | 22 | "None: no limit" |
20 | 23 | raise NotImplementedError() |
24 | ||
21 | 25 | def read(self): |
22 | 26 | raise NotImplementedError() |
27 | ||
23 | 28 | def write(self, data): |
24 | 29 | raise NotImplementedError() |
30 | ||
25 | 31 | def saveInto(self, filename): |
26 | 32 | output = FileOutputStream(filename) |
27 | 33 | self.editor.writeInto(output) |
34 | ||
28 | 35 | |
29 | 36 | def computeCRC32(data): |
30 | 37 | "Compute CRC-32 of data string. Result is a positive integer." |
34 | 41 | else: |
35 | 42 | return 1 << 32 |
36 | 43 | |
44 | ||
37 | 45 | class PngInjecter(Injecter): |
38 | 46 | MAGIC = "HACHOIR" |
39 | 47 | |
40 | 48 | def getMaxSize(self): |
41 | 49 | return None |
50 | ||
42 | 51 | def read(self): |
43 | 52 | for field in self.editor: |
44 | 53 | if field.name.startswith("text[") \ |
45 | and field["keyword"].value == self.MAGIC: | |
54 | and field["keyword"].value == self.MAGIC: | |
46 | 55 | return field["text"].value |
47 | 56 | return None |
48 | 57 | |
52 | 61 | size = len(data) |
53 | 62 | crc = computeCRC32(tag + data) |
54 | 63 | chunk = NewFieldSet(self.editor, "inject[]") |
55 | chunk.insert( EditableInteger(chunk, "size", False, 32, size) ) | |
56 | chunk.insert( EditableBytes(chunk, "tag", tag) ) | |
57 | chunk.insert( EditableBytes(chunk, "content", data) ) | |
58 | chunk.insert( EditableInteger(chunk, "crc32", False, 32, crc) ) | |
64 | chunk.insert(EditableInteger(chunk, "size", False, 32, size)) | |
65 | chunk.insert(EditableBytes(chunk, "tag", tag)) | |
66 | chunk.insert(EditableBytes(chunk, "content", data)) | |
67 | chunk.insert(EditableInteger(chunk, "crc32", False, 32, crc)) | |
59 | 68 | self.editor.insertBefore("end", chunk) |
69 | ||
60 | 70 | |
61 | 71 | class MpegAudioInjecter(Injecter): |
62 | 72 | MAX_PACKET_SIZE = 2048 # bytes between each frame |
90 | 100 | print("Packet size: %s" % self.packet_size) |
91 | 101 | print("Check input message") |
92 | 102 | if "\xff" in data: |
93 | raise InjecterError("Sorry, MPEG audio injecter disallows 0xFF byte") | |
103 | raise InjecterError( | |
104 | "Sorry, MPEG audio injecter disallows 0xFF byte") | |
94 | 105 | |
95 | 106 | # print "Check message size" |
96 | 107 | # maxbytes = self.getMaxSize() |
106 | 117 | padding = data[index:index + self.packet_size] |
107 | 118 | name = "frame[%u]" % field_index |
108 | 119 | print("Insert %s before %s" % (len(padding), name)) |
109 | output.insertAfter(name, EditableString(output, "padding[]", "fixed", padding) ) | |
120 | output.insertAfter(name, EditableString( | |
121 | output, "padding[]", "fixed", padding)) | |
110 | 122 | index += self.packet_size |
111 | 123 | field_index += 2 |
112 | 124 | |
119 | 131 | PngFile: PngInjecter, |
120 | 132 | MpegAudioFile: MpegAudioInjecter, |
121 | 133 | } |
134 | ||
122 | 135 | |
123 | 136 | def main(): |
124 | 137 | if len(argv) != 2: |
152 | 165 | |
153 | 166 | if __name__ == "__main__": |
154 | 167 | main() |
155 |
2 | 2 | from hachoir.parser.container.swf import SOUND_CODEC_MP3 |
3 | 3 | from sys import stderr, exit, argv |
4 | 4 | |
5 | ||
5 | 6 | class JpegExtractor: |
7 | ||
6 | 8 | def __init__(self): |
7 | 9 | self.jpg_index = 1 |
8 | 10 | self.snd_index = 1 |
27 | 29 | if 32 < header.size: |
28 | 30 | if self.verbose: |
29 | 31 | print("Use JPEG table: %s" % header.path) |
30 | header = field.root.stream.readBytes(header.absolute_address, (header.size-16)//8) | |
32 | header = field.root.stream.readBytes( | |
33 | header.absolute_address, (header.size - 16) // 8) | |
31 | 34 | else: |
32 | 35 | header = "" |
33 | 36 | else: |
50 | 53 | assert data[:1] == b'\xFF' |
51 | 54 | output.write(data) |
52 | 55 | elif field.name.startswith("sound_blk") \ |
53 | and "music_data" in field: | |
56 | and "music_data" in field: | |
54 | 57 | data = field["music_data"].value |
55 | 58 | if data: |
56 | 59 | assert data[0] == '\xFF' |
84 | 87 | self.extractFormat2(field) |
85 | 88 | |
86 | 89 | # Extract sound |
87 | #self.extractSound(parser) | |
90 | # self.extractSound(parser) | |
88 | 91 | self.extractSound2(parser) |
89 | 92 | |
90 | 93 | # Does it extract anything? |
94 | 97 | print("No sound found.") |
95 | 98 | |
96 | 99 | JpegExtractor().main() |
97 |