def export(self): """Export the data.""" global active_thread self.view = self.window.active_view() if self.handshake != -1 and self.handshake == self.view.id(): try: sublime.set_timeout( lambda: sublime.status_message("Writing..."), 0) self.row = self.view.rowcol(self.view.size())[0] + 1 self.hex_buffer = StringIO( self.view.substr(sublime.Region(0, self.view.size()))) self.thread = ThreadedWrite(self.hex_buffer, self.export_path, parse_view_data, self.row) self.thread.start() self.export_thread() active_thread = self.thread except Exception: print(str(traceback.format_exc())) error("Failed to export to " + self.export_path) self.reset() return else: error("Hex view is no longer in focus! File not saved.") self.reset()
def run(self, hash_algorithm=None, panel=False): global active_thread if active_thread is not None and active_thread.is_alive(): error("HexViewer is already checksumming a file!\nPlease run the abort command to stop the current checksum.") else: if not panel: self.get_checksum(hash_algorithm) else: self.window.show_quick_panel(VALID_HASH, self.select_checksum)
def run(self, hash_algorithm=None, panel=False): """Run command.""" if active_thread is not None and active_thread.is_alive(): error("HexViewer is already checksumming a file!\n" "Please run the abort command to stop the current checksum.") else: if not panel: self.get_checksum(hash_algorithm) else: self.window.show_quick_panel(VALID_HASH, self.select_checksum)
def discard_changes(self, value): if value.strip().lower() == "yes": if self.switch_type == "hex": view = sublime.active_window().active_view() if self.handshake == view.id(): view.set_scratch(True) self.read_bin(self.file_name) else: error("Target view is no longer in focus! Hex view aborted.") else: self.read_file(self.file_name) self.reset()
def prepare_export(self, file_path): self.export_path = file_path if exists(dirname(file_path)): if exists(file_path): self.window.show_input_panel("Overwrite File? (yes | no):", "no", self.overwrite, None, self.reset) else: self.export() else: error("Directory does not exist!") self.export_path = self.view.settings().get("hex_viewer_file_name") self.export_panel()
def run(self, edit): viewer = hv_settings("external_viewer", {}).get("viewer", "") if not exists(viewer): error("Can't find the external hex viewer!") return file_name = self.view.file_name() if file_name is not None and exists(file_name): cmd = [viewer] + hv_settings("external_viewer", {}).get("args", []) for x in range(0, len(cmd)): cmd[x] = cmd[x].replace("${FILE}", file_name) subprocess.Popen(cmd)
def discard_changes(self, value): """Discard changes.""" if value.strip().lower() == "yes": if self.switch_type == "hex": view = sublime.active_window().active_view() if self.handshake == view.id(): view.set_scratch(True) self.read_bin(self.file_name) else: error("Target view is no longer in focus! Hex view aborted.") else: self.read_file(self.file_name) self.reset()
def run(self): """Run command.""" if active_thread is not None and active_thread.is_alive(): error("HexViewer is already exporting a file!\nPlease run the abort command to stop the current export.") else: self.view = self.window.active_view() # Identify view if self.handshake != -1 and self.handshake == self.view.id(): self.reset() self.handshake = self.view.id() self.export_path = self.view.settings().get("hex_viewer_file_name") self.export_panel()
def run(self, edit): """Run command.""" viewer = common.hv_settings("external_viewer", {}).get("viewer", "") if not exists(viewer): error("Can't find the external hex viewer!") return file_name = self.window.extract_variables().get('file') if file_name is not None and exists(file_name): cmd = [viewer] + common.hv_settings("external_viewer", {}).get("args", []) for x in range(0, len(cmd)): cmd[x] = cmd[x].replace("${FILE}", file_name) subprocess.Popen(cmd)
def go_to_address(self, address): """Go to the specified address.""" view = self.window.active_view() if self.handshake != -1 and self.handshake == view.id(): # Adress offset for line address_offset = view.settings().get('hex_viewer_starting_address', 0) group_size = view.settings().get("hex_viewer_bits", None) bytes_wide = view.settings().get("hex_viewer_actual_bytes", None) if group_size is None and bytes_wide is None: return group_size = group_size / common.BITS_PER_BYTE # Go to address try: # Address wanted wanted = int(address, 16) - address_offset assert wanted >= 0, "Address does not exist!" # Calculate row row = int(wanted / (bytes_wide)) # Byte offset into final row byte = wanted % (bytes_wide) # Calculate byte number Offset Char # # wanted_char byte # ------------ = ----------- => wanted_char + 11 = column # total_chars total_bytes # column = int((float(byte) / group_size) * ((group_size) * 2 + 1)) + common.ADDRESS_OFFSET # Go to address and focus pt = view.text_point(row, column) view.sel().clear() view.sel().add(pt) view.show_at_center(pt) # Highlight self.window.run_command('hex_highlighter') except Exception: pass else: error("Hex view is no longer in focus! Find address canceled.") self.reset()
def read_bin(self, file_name): global active_thread self.abort = False self.current_view = self.view self.thread = ReadBin(file_name, self.bytes_wide, self.group_size) file_size = float(self.thread.file_size) * 0.001 max_file_size = float(hv_settings("max_file_size_kb", DEFAULT_MAX_FILE_SIZE)) if file_size > max_file_size: viewer = hv_settings("external_viewer", {}).get("viewer", "") if exists(viewer): self.view.run_command("hex_external_viewer") else: error("File size exceeded HexViewers configured max limit of %s KB" % str(max_file_size)) self.reset_thread() else: self.thread.start() self.handle_thread() active_thread = self.thread
def run(self, edit): """Run command.""" viewer = common.hv_settings("external_viewer", {}).get("viewer", "") if not exists(viewer): error("Can't find the external hex viewer!") return file_name = self.window.extract_variables().get('file') if file_name is not None and exists(file_name): cmd = [viewer] + common.hv_settings("external_viewer", {}).get( "args", []) for x in range(0, len(cmd)): cmd[x] = cmd[x].replace("${FILE}", file_name) subprocess.Popen(cmd)
def prepare_export(self, file_path): """Prepare to export.""" self.export_path = file_path if exists(dirname(file_path)): if exists(file_path): self.window.show_input_panel( "Overwrite File? (yes | no):", "no", self.overwrite, None, self.reset ) else: self.export() else: error("Directory does not exist!") self.export_path = self.view.settings().get("hex_viewer_file_name") self.export_panel()
def export_thread(self): ratio = float(self.thread.chunk) / float(self.thread.chunks) percent = int(ratio * 10) leftover = 10 - percent message = "[" + "-" * percent + ">" + "-" * leftover + ( "] %3d%%" % int(ratio * 100)) + " chunks written" sublime.status_message(message) if not self.thread.is_alive(): if self.thread.abort is True: notify("Write aborted!") sublime.set_timeout(lambda: self.reset_thread(), 500) else: status = self.thread.status self.reset_thread() if status == WRITE_GOOD: sublime.set_timeout(lambda: self.finish_export(), 500) else: error("Failed to export to " + self.export_path) else: sublime.set_timeout(lambda: self.export_thread(), 500)
def read_bin(self, file_name): """Read the binary file.""" global active_thread self.abort = False self.current_view = self.view self.thread = ReadBin(file_name, self.bytes_wide, self.group_size, self.starting_address) file_size = float(self.thread.file_size) * 0.001 max_file_size = float(common.hv_settings("max_file_size_kb", DEFAULT_MAX_FILE_SIZE)) if file_size > max_file_size: viewer = common.hv_settings("external_viewer", {}).get("viewer", "") if exists(viewer): self.view.run_command("hex_external_viewer") else: error("File size exceeded HexViewers configured max limit of %s KB" % str(max_file_size)) self.reset_thread() else: self.thread.start() self.handle_thread() active_thread = self.thread
def read_bin(self, file_name): """Read the binary file.""" global active_thread self.abort = False self.thread = ReadBin(file_name, self.bytes_wide, self.group_size, self.starting_address) if self.is_file_too_big(): viewer = common.hv_settings("external_viewer", {}).get("viewer", "") if exists(viewer): self.window.run_command("hex_external_viewer") else: error( "File size exceeded HexViewers configured max limit of %s KB" % str( common.hv_settings("max_file_size_kb", DEFAULT_MAX_FILE_SIZE) ) ) self.reset_thread() else: self.thread.start() self.handle_thread() active_thread = self.thread
def export_thread(self): """Thread the export.""" ratio = float(self.thread.chunk) / float(self.thread.chunks) percent = int(ratio * 10) leftover = 10 - percent message = "[" + "-" * percent + ">" + "-" * leftover + ("] %3d%%" % int(ratio * 100)) + " chunks written" sublime.status_message(message) if not self.thread.is_alive(): if self.thread.abort is True: notify("Write aborted!") sublime.set_timeout(self.reset_thread, 500) else: status = self.thread.status self.reset_thread() if status == WRITE_GOOD: sublime.set_timeout(self.finish_export, 500) else: error("Failed to export to " + self.export_path) else: sublime.set_timeout(self.export_thread, 500)
def export(self): """Export the data.""" global active_thread self.view = self.window.active_view() if self.handshake != -1 and self.handshake == self.view.id(): try: sublime.set_timeout(lambda: sublime.status_message("Writing..."), 0) self.row = self.view.rowcol(self.view.size())[0] + 1 self.hex_buffer = StringIO(self.view.substr(sublime.Region(0, self.view.size()))) self.thread = ThreadedWrite(self.hex_buffer, self.export_path, parse_view_data, self.row) self.thread.start() self.export_thread() active_thread = self.thread except Exception: print(str(traceback.format_exc())) error("Failed to export to " + self.export_path) self.reset() return else: error("Hex view is no longer in focus! File not saved.") self.reset()
def run(self, bits=None, byte_array=None, starting_address=0): """Run the command.""" self.starting_address = starting_address if active_thread is not None and active_thread.is_alive(): error( "HexViewer is already converting a file!\n" "Please run the abort command to stop the current conversion." ) return # If thread is active cancel thread if self.thread is not None and self.thread.is_alive(): self.abort_hex_load() return # Init Buffer file_name = self.buffer_init(bits, byte_array) # Identify view if self.handshake != -1 and self.handshake == self.view.id(): self.reset() self.handshake = self.view.id() if file_name is not None and exists(file_name): # Decide whether to read in as a binary file or a traditional file if self.view.settings().has("hex_viewer_file_name"): self.view_type = "hex" if common.is_hex_dirty(self.view): self.file_name = file_name if bits is None and byte_array is None: self.switch_type = "file" else: self.switch_type = "hex" self.discard_panel() else: if bits is None and byte_array is None: # Switch back to traditional output self.read_file(file_name) else: # Reload hex with new settings self.read_bin(file_name) else: # We are going to swap out the current file for hex output # So as not to clutter the screen. Changes need to be saved # Or they will be lost if self.view.is_dirty(): self.file_name = file_name self.switch_type = "hex" self.discard_panel() else: # Switch to hex output self.read_bin(file_name) else: if file_name is None: error("View does not exist on disk!") else: error("%s does not exist on disk!" % basename(file_name))
def apply_edit(self, value): """Apply edits.""" edits = "" self.view = self.window.active_view() # Is this the same view as earlier? if self.handshake != -1 and self.handshake == self.view.id(): total_chars = self.total_bytes * 2 selection = self.line["selection"].replace(" ", "") # Transform string if provided if re.match("^s\:", value) is not None: edits = hexlify(value[2:len(value)].encode("ascii")).decode("ascii") else: edits = value.replace(" ", "").lower() # See if change occured and if changes are valid if len(edits) != total_chars: self.edit_panel(value, "Unexpected # of bytes!") return elif re.match("[\da-f]{" + str(total_chars) + "}", edits) is None: self.edit_panel(value, "Invalid data!") return elif selection != edits: # Get previous dirty markers before modifying buffer regions = self.view.get_regions("hex_edit") # Construct old and new data for diffs edits = self.line["data1"] + edits + self.line["data2"] original = self.line["data1"] + selection + self.line["data2"] # Initialize ascii_str = " :" start = 0 ascii_start_pos = self.ascii_pos hex_start_pos = self.line["range"].begin() + common.ADDRESS_OFFSET end = len(edits) count = 1 change_start = None # Reconstruct line l_buffer = self.line["address"] while start < end: byte_end = start + 2 value = edits[start:byte_end] # Diff data and mark changed bytes if value != original[start:byte_end]: if change_start is None: change_start = [hex_start_pos, ascii_start_pos] # Check if group end if count == self.group_size: regions.append(sublime.Region(change_start[0], hex_start_pos + 2)) change_start[0] = None else: # Check if after group end if change_start[0] is None: change_start[0] = hex_start_pos # Check if group end if count == self.group_size: regions.append(sublime.Region(change_start[0], hex_start_pos + 2)) change_start[0] = None elif change_start is not None: if self.view.score_selector(hex_start_pos - 1, 'raw.nibble.lower'): if change_start[0] is not None: regions.append(sublime.Region(change_start[0], hex_start_pos)) else: if change_start[0] is not None: regions.append(sublime.Region(change_start[0], hex_start_pos - 1)) regions.append(sublime.Region(change_start[1], ascii_start_pos)) change_start = None # Write bytes and add space and at group region end l_buffer += value if count == self.group_size: l_buffer += " " hex_start_pos += 1 count = 0 # Copy valid printible ascii chars over or substitute with "." dec = unpack("=B", unhexlify(value))[0] ascii_str += chr(dec) if dec in range(32, 127) else "." start += 2 count += 1 hex_start_pos += 2 ascii_start_pos += 1 # Check for end of line case for highlight if change_start is not None: if change_start[0] is not None: regions.append(sublime.Region(change_start[0], hex_start_pos)) regions.append(sublime.Region(change_start[1], ascii_start_pos)) change_start = None # Append ascii chars to line accounting for missing bytes in line delta = int(self.bytes_wide) - len(edits) / 2 group_space = int(delta / self.group_size) + (1 if delta % self.group_size else 0) l_buffer += " " * int(group_space + delta * 2) + ascii_str # Apply buffer edit self.view.sel().clear() self.view.set_read_only(False) HexEditGlobal.bfr = l_buffer HexEditGlobal.region = self.line["range"] self.view.run_command("hex_edit_apply") HexEditGlobal.clear() self.view.set_read_only(True) self.view.sel().add(sublime.Region(self.start_pos, self.end_pos)) # Underline if required if self.highlight_style == sublime.DRAW_EMPTY_AS_OVERWRITE: regions = common.underline(regions) # Highlight changed bytes self.view.add_regions( "hex_edit", regions, self.highlight_scope, self.highlight_icon, self.highlight_style ) # Update selection self.window.run_command('hex_highlighter') else: error("Hex view is no longer in focus! Edit Failed.") # Clean up self.reset()
def apply_edit(self, value): """Apply edits.""" edits = "" self.view = self.window.active_view() # Is this the same view as earlier? if self.handshake != -1 and self.handshake == self.view.id(): total_chars = self.total_bytes * 2 selection = self.line["selection"].replace(" ", "") # Transform string if provided if re.match("^s\:", value) is not None: edits = hexlify( value[2:len(value)].encode("ascii")).decode("ascii") else: edits = value.replace(" ", "").lower() # See if change occured and if changes are valid if len(edits) != total_chars: self.edit_panel(value, "Unexpected # of bytes!") return elif re.match("[\da-f]{" + str(total_chars) + "}", edits) is None: self.edit_panel(value, "Invalid data!") return elif selection != edits: # Get previous dirty markers before modifying buffer regions = self.view.get_regions("hex_edit") # Construct old and new data for diffs edits = self.line["data1"] + edits + self.line["data2"] original = self.line["data1"] + selection + self.line["data2"] # Initialize ascii_str = " :" start = 0 ascii_start_pos = self.ascii_pos hex_start_pos = self.line["range"].begin( ) + common.ADDRESS_OFFSET end = len(edits) count = 1 change_start = None # Reconstruct line l_buffer = self.line["address"] while start < end: byte_end = start + 2 value = edits[start:byte_end] # Diff data and mark changed bytes if value != original[start:byte_end]: if change_start is None: change_start = [hex_start_pos, ascii_start_pos] # Check if group end if count == self.group_size: regions.append( sublime.Region(change_start[0], hex_start_pos + 2)) change_start[0] = None else: # Check if after group end if change_start[0] is None: change_start[0] = hex_start_pos # Check if group end if count == self.group_size: regions.append( sublime.Region(change_start[0], hex_start_pos + 2)) change_start[0] = None elif change_start is not None: if self.view.score_selector(hex_start_pos - 1, 'raw.nibble.lower'): if change_start[0] is not None: regions.append( sublime.Region(change_start[0], hex_start_pos)) else: if change_start[0] is not None: regions.append( sublime.Region(change_start[0], hex_start_pos - 1)) regions.append( sublime.Region(change_start[1], ascii_start_pos)) change_start = None # Write bytes and add space and at group region end l_buffer += value if count == self.group_size: l_buffer += " " hex_start_pos += 1 count = 0 # Copy valid printible ascii chars over or substitute with "." dec = unpack("=B", unhexlify(value))[0] ascii_str += chr(dec) if dec in range(32, 127) else "." start += 2 count += 1 hex_start_pos += 2 ascii_start_pos += 1 # Check for end of line case for highlight if change_start is not None: if change_start[0] is not None: regions.append( sublime.Region(change_start[0], hex_start_pos)) regions.append( sublime.Region(change_start[1], ascii_start_pos)) change_start = None # Append ascii chars to line accounting for missing bytes in line delta = int(self.bytes_wide) - len(edits) / 2 group_space = int(delta / self.group_size) + ( 1 if delta % self.group_size else 0) l_buffer += " " * int(group_space + delta * 2) + ascii_str # Apply buffer edit self.view.sel().clear() self.view.set_read_only(False) HexEditGlobal.bfr = l_buffer HexEditGlobal.region = self.line["range"] self.view.run_command("hex_edit_apply") HexEditGlobal.clear() self.view.set_read_only(True) self.view.sel().add( sublime.Region(self.start_pos, self.end_pos)) # Underline if required if self.highlight_style == sublime.DRAW_EMPTY_AS_OVERWRITE: regions = common.underline(regions) # Highlight changed bytes self.view.add_regions("hex_edit", regions, self.highlight_scope, self.highlight_icon, self.highlight_style) # Update selection self.window.run_command('hex_highlighter') else: error("Hex view is no longer in focus! Edit Failed.") # Clean up self.reset()