36 Star 262 Fork 58

compilelife / bitinsight

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
viewdata.py 8.95 KB
一键复制 编辑 原始数据 按行查看 历史
from PySide2 import QtCore, QtWidgets, QtGui
from table import BitPos
from bitstream import *
import mmap
import weakref
import platform
class DataViewer:
def __init__(self, editor):
self.editor = editor
def to_data_pos(self, cursor_pos):
pass
def moveto(self, pos:BitPos):
pass
def highlight(self,begin: BitPos,end: BitPos):
pass
def clear_higlight(self):
self.editor.setExtraSelections([])
class ByteViewer(DataViewer):
def __init__(self, editor:QtWidgets.QPlainTextEdit):
super(ByteViewer, self).__init__(editor)
def __to_cursor_pos(self, pos:BitPos):
return pos.byte * 3 + (1 if pos.bit >= 4 else 0)
def to_data_pos(self, cursor_pos):
byte = int(cursor_pos / 3)
bit = cursor_pos % 3
if bit == 1:
bit = 4
elif bit == 2: #空格处处理为下一个字节
bit = 0
byte += 1
return BitPos(byte, bit)
def moveto(self, pos:BitPos):
cursor = self.editor.textCursor()
cursor.setPosition(self.__to_cursor_pos(pos))
self.editor.setTextCursor(cursor)
def highlight(self,begin: BitPos,end: BitPos):
selection = QtWidgets.QTextEdit.ExtraSelection()
selection.cursor = self.editor.textCursor()
selection.cursor.setPosition(self.__to_cursor_pos(begin))
selection.cursor.setPosition(self.__to_cursor_pos(end) + (0 if end.bit in [0,4] else 1), QtGui.QTextCursor.KeepAnchor)
selection.format.setBackground(QtGui.QColor(0,255,0))
self.editor.setExtraSelections([selection])
def load(self,data):
self.editor.clear()
bytestr = []
for b in data:
bytestr.append(format(b, '02x'))
self.editor.setPlainText(' '.join(bytestr)+' ')
class BitViewer(DataViewer):
def __init__(self, editor:QtWidgets.QPlainTextEdit):
super(BitViewer, self).__init__(editor)
def __to_cursor_pos(self, pos:BitPos):
return pos.byte * 9 + pos.bit
def to_data_pos(self, cursor_pos):
byte = int(cursor_pos / 9)
bit = cursor_pos % 9
if bit == 8: #空格位置处理为下一个字节开始
byte += 1
bit = 0
return BitPos(byte, bit)
def moveto(self, pos:BitPos):
cursor = self.editor.textCursor()
cursor.setPosition(self.__to_cursor_pos(pos))
self.editor.setTextCursor(cursor)
def highlight(self,begin: BitPos,end: BitPos):
print("highlight %s=>%s "%(str(begin),str(end)))
selection = QtWidgets.QTextEdit.ExtraSelection()
selection.cursor = self.editor.textCursor()
selection.cursor.setPosition(self.__to_cursor_pos(begin))
selection.cursor.setPosition(self.__to_cursor_pos(end), QtGui.QTextCursor.KeepAnchor)
selection.format.setBackground(QtGui.QColor(0,255,0))
self.editor.setExtraSelections([selection])
def load(self,data):
self.editor.clear()
bitstr = []
for b in data:
bitstr.append(format(b, '08b'))
self.editor.setPlainText(' '.join(bitstr)+' ')
class MemoryViewer(DataViewer):
def __init__(self, mem):
super(MemoryViewer, self).__init__(DataViewerEditor(self))
self._highlight = []
self._impl = ByteViewer(self.editor)
self._bitstream = BitStream(mem)
self.valid_range = [0, len(mem)] # end pos not include
self.mem = mem
self.limit_range(0, 1024)
def get_pos(self):
return self._from_impl_pos(self._impl.to_data_pos(self.editor.textCursor().position()))
def is_bit_mode(self):
return type(self._impl) == BitViewer
def _to_impl_pos(self, pos):
return BitPos(pos.byte - self.valid_range[0], pos.bit)
def _from_impl_pos(self, pos):
return BitPos(pos.byte + self.valid_range[0], pos.bit)
def set_bit_mode(self,bit = False):
if self.is_bit_mode() == bit:
return
pos = self.get_pos()
self._impl = BitViewer(self.editor) if bit else ByteViewer(self.editor)
self.__load_to_impl()
self._impl.moveto(self._to_impl_pos(pos))
if len(self._highlight) > 0:
self._impl.highlight(self._to_impl_pos(self._highlight[0]), self._to_impl_pos(self._highlight[1]))
def moveto(self, pos:BitPos):
self._impl.moveto(self._to_impl_pos(pos))
def highlight(self, begin:BitPos, end:BitPos):
self._highlight = [begin, end]
self._impl.highlight(self._to_impl_pos(begin), self._to_impl_pos(end))
def get_bitstream(self):
cursor = self.editor.textCursor()
begin = cursor.selectionStart()
pos = self._from_impl_pos(self._impl.to_data_pos(begin))
self._bitstream.moveto(pos.byte, pos.bit)
if cursor.hasSelection():
end = cursor.selectionEnd()
pos = self._from_impl_pos(self._impl.to_data_pos(end))
self._bitstream.set_end_pos(pos.byte, pos.bit)
else:
self._bitstream.set_end_pos(self.valid_range[1], 0)
return self._bitstream
def __load_to_impl(self):
self._impl.load(self.mem[self.valid_range[0]:self.valid_range[1]])
def limit_range(self, from_include, to_exclude):
if to_exclude > len(self.mem):
to_exclude = len(self.mem)
if from_include < 0:
from_include = 0
self.valid_range = [from_include, to_exclude]
self.__load_to_impl()
class FileViewer(MemoryViewer):
def __init__(self, path):
with open(path, 'rb') as f:
mem = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ)
super(FileViewer, self).__init__(mem)
def __del__(self):
self.mem.close()
class DataNav(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.viewer = None
scope_layout = QtWidgets.QHBoxLayout()
self.begin = QtWidgets.QLineEdit()
scope_layout.addWidget(self.begin)
scope_layout.addWidget(QtWidgets.QLabel('-'))
self.end = QtWidgets.QLineEdit()
scope_layout.addWidget(self.end)
btn = QtWidgets.QPushButton('加载')
btn.clicked.connect(self.__load)
scope_layout.addWidget(btn)
nav_layout = QtWidgets.QVBoxLayout()
self.curpos = QtWidgets.QLabel('当前位置: ')
nav_layout.addWidget(self.curpos)
self.size = QtWidgets.QLabel('大小: ')
nav_layout.addWidget(self.size)
nav_layout.addLayout(scope_layout)
self.setLayout(nav_layout)
def __load(self):
if self.viewer == None:
return
begin = int(self.begin.text())
if self.end.text() != '':
end = int(self.end.text())
else:
end = begin+1024
self.viewer.limit_range(begin, end)
self.__update_pos()
self.__update_size()
def __update_size(self):
self.size.setText('大小: [%d => %d) / %d'%(self.viewer.valid_range[0], self.viewer.valid_range[1], len(self.viewer.mem)))
def __update_pos(self):
pos = self.viewer.get_pos()
self.curpos.setText('当前位置: '+str(pos))
def set_data_viewer(self,viewer):
self.viewer = viewer
self.viewer.editor.cursorPositionChanged.connect(self.__update_pos)
self.viewer.editor.cursorPositionChanged.connect(self.__update_size)
self.__update_pos()
self.__update_size()
class DataViewerEditor(QtWidgets.QPlainTextEdit):
analyse_requested = QtCore.Signal(BitStream)
default_analyse_requested = QtCore.Signal(BitStream)
def __init__(self, viewer: MemoryViewer):
super(DataViewerEditor, self).__init__();
family = 'monospace'
if platform.system() == 'Darwin':
family = 'Menlo'
self.setFont(QtGui.QFont(family))
self.__viewer = weakref.ref(viewer)
self.setCursorWidth(6)
self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
self.__actions = []
self.__add_action('执行默认解析器', 'Ctrl+D', self.default_analyse)
self.__add_action('解析...', 'Ctrl+P', self.analyse)
self.__add_action('查找...', 'Ctrl+F', self.search)
self.__add_action('切换二进制/十六机制', 'Ctrl+M', self.switch_mode)
def __add_action(self, name, key, proc):
action = QtWidgets.QAction(name)
action.setShortcut(QtGui.QKeySequence(key))
action.triggered.connect(proc)
self.__actions.append(action)
self.addAction(action)
def search(self):
(text, ok) = QtWidgets.QInputDialog.getText(self, '请输入', '要搜索的字符串')
if ok:
self.find(text)
def set_default_parser(self,name):
self.__actions[0].setText('执行'+name)
def default_analyse(self):
self.default_analyse_requested.emit(self.__viewer().get_bitstream())
def analyse(self):
self.analyse_requested.emit(self.__viewer().get_bitstream())
def switch_mode(self):
self.__viewer().set_bit_mode(not self.__viewer().is_bit_mode())
Python
1
https://gitee.com/compilelife/bitinsight.git
git@gitee.com:compilelife/bitinsight.git
compilelife
bitinsight
bitinsight
master

搜索帮助