├── .gitignore ├── LICENSE.md ├── README.md ├── lib ├── hex-view.coffee └── hex.coffee ├── menus └── hex.cson ├── package.json └── styles └── hex.less /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules 4 | images 5 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | This software is released under the MIT license: 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hex Viewer for [Atom](http://atom.io) 2 | 3 | View the hex dump of any file 4 | 5 | ## Install 6 | 7 | apm install hex 8 | 9 | If you want a shortcut, you can open your `keymap.cson` file and add this: 10 | 11 | '.editor:not(.mini)': 12 | 'shift-ctrl-h': 'hex:view' 13 | 14 | --- 15 | 16 | ![Screenshot](https://cloud.githubusercontent.com/assets/7937/2545687/a57ab926-b61e-11e3-9460-40b6733313bc.gif) 17 | -------------------------------------------------------------------------------- /lib/hex-view.coffee: -------------------------------------------------------------------------------- 1 | {$, ScrollView} = require 'atom-space-pen-views' 2 | {Disposable} = require 'atom' 3 | path = require 'path' 4 | fs = require 'fs-plus' 5 | entities = null 6 | 7 | module.exports = 8 | class HexView extends ScrollView 9 | @content: -> 10 | @div class: 'hex-view padded pane-item', tabindex: -1, => 11 | @div class: 'hex-dump', outlet: 'hexDump' 12 | 13 | initialize: ({@filePath}) => 14 | super 15 | 16 | attached: -> 17 | entities ?= require 'entities' 18 | @hexFile(@filePath) 19 | 20 | @hexDump.css 21 | 'font-family': atom.config.get('editor.fontFamily') 22 | 'font-size': atom.config.get('editor.fontSize') 23 | 24 | hexFile: (filePath) -> 25 | stream = fs.ReadStream(filePath) 26 | stream.on 'data', (chunk) => 27 | @hex chunk if @hexDump.is(':empty') 28 | 29 | getPath: -> @filePath 30 | 31 | getURI: -> @filePath 32 | 33 | getTitle: -> "#{path.basename(@getPath())} Hex" 34 | 35 | # NOP to remove deprecation. This kind of sucks 36 | onDidChangeTitle: -> 37 | new Disposable() 38 | 39 | onDidChangeModified: -> 40 | new Disposable() 41 | 42 | # Based on "node-hex" by Gabriel Llamas 43 | # https://github.com/gagle/node-hex 44 | 45 | hex: (buffer) => 46 | bytesPerLine = atom.config.get('hex.bytesPerLine') 47 | rows = Math.ceil(buffer.length / bytesPerLine) 48 | last = buffer.length % bytesPerLine or bytesPerLine 49 | offsetLength = buffer.length.toString(16).length 50 | offsetLength = 6 if offsetLength < 6 51 | 52 | offset = "Offset:" 53 | hex = "" 54 | ascii = "" 55 | 56 | i = 0 57 | while i < bytesPerLine 58 | offset += " #{zero(i, 2)}" 59 | i++ 60 | 61 | b = 0 62 | lastBytes = undefined 63 | v = undefined 64 | i = 0 65 | 66 | while i < rows 67 | hex += "#{zero(b, offsetLength)}:" 68 | lastBytes = (if i is rows - 1 then last else bytesPerLine) 69 | 70 | j = 0 71 | while j < lastBytes 72 | hex += " #{zero(buffer[b], 2)}" 73 | b++ 74 | j++ 75 | 76 | b -= lastBytes 77 | 78 | j = 0 79 | while j < lastBytes 80 | v = buffer[b] 81 | if (v > 31 and v < 127) or v > 159 82 | ascii += entities.encodeHTML(String.fromCharCode(v)) 83 | else 84 | ascii += "." 85 | b++ 86 | j++ 87 | 88 | hex += "
" 89 | ascii += "
" 90 | i++ 91 | 92 | @hexDump.append "
#{offset}
" 93 | @hexDump.append "
#{hex}
" 94 | @hexDump.append "
#{ascii}
" 95 | 96 | zero = (n, max) -> 97 | n = n.toString(16).toUpperCase() 98 | n = "0#{n}" while n.length < max 99 | n 100 | -------------------------------------------------------------------------------- /lib/hex.coffee: -------------------------------------------------------------------------------- 1 | fs = require 'fs-plus' 2 | HexView = null 3 | 4 | module.exports = 5 | config: 6 | bytesPerLine: 7 | type: 'integer' 8 | default: 16 9 | minimum: 1 10 | 11 | activate: -> 12 | atom.commands.add 'atom-workspace', 'hex:view', => createView() 13 | @openerDisposable = atom.workspace.addOpener(openURI) 14 | 15 | deactivate: -> 16 | @openerDisposable.dispose() 17 | 18 | openURI = (uriToOpen) -> 19 | pathname = uriToOpen.replace 'hex://', '' 20 | return unless uriToOpen.substr(0, 4) is 'hex:' 21 | 22 | HexView ?= require './hex-view' 23 | new HexView(filePath: pathname) 24 | 25 | createView = -> 26 | paneItem = atom.workspace.getActivePaneItem() 27 | filePath = paneItem.getPath() 28 | if paneItem and fs.isFileSync(filePath) 29 | atom.workspace.open "hex://#{filePath}" 30 | else 31 | console.warn "File (#{filePath}) does not exists" 32 | -------------------------------------------------------------------------------- /menus/hex.cson: -------------------------------------------------------------------------------- 1 | 'menu': [ 2 | { 3 | 'label': 'Packages' 4 | 'submenu': [ 5 | 'label': 'Hex View', 6 | 'command': 'hex:view' 7 | ] 8 | } 9 | ] 10 | 11 | 'context-menu': 12 | '.image-view': [ 13 | { 14 | 'label': 'Hex View', 15 | 'command': 'hex:view', 16 | } 17 | ] 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hex", 3 | "main": "./lib/hex", 4 | "version": "0.6.2", 5 | "description": "Hex Viewer for Atom", 6 | "repository": "https://github.com/AbeEstrada/atom-hex", 7 | "license": "MIT", 8 | "engines": { 9 | "atom": ">0.50.0 <2.0.0" 10 | }, 11 | "dependencies": { 12 | "fs-plus": "^2.0.0", 13 | "entities": "^1.0.0", 14 | "atom-space-pen-views": "^2.0.3" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /styles/hex.less: -------------------------------------------------------------------------------- 1 | @import "ui-variables"; 2 | 3 | atom-pane-container atom-pane .item-views { 4 | overflow: auto; 5 | .hex-view { 6 | padding-top: 0; 7 | overflow: auto; 8 | } 9 | } 10 | .hex-dump { 11 | font-family: Menlo, Monaco, Consolas, "Courier New", monospace; 12 | } 13 | .hex-dump header { 14 | padding-top: 10px; 15 | white-space: nowrap; 16 | } 17 | .hex-dump .hex { 18 | float: left; 19 | margin: 10px 0 0 0; 20 | padding: 0 20px 0 0; 21 | white-space: nowrap; 22 | overflow: hidden; 23 | } 24 | .hex-dump .ascii { 25 | margin: 10px 0 0 0; 26 | white-space: nowrap; 27 | overflow: hidden; 28 | } 29 | --------------------------------------------------------------------------------